1 //===- LinkerTest.cpp -----------------------------------------------------===//
2 //
3 // The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include "LinkerTest.h"
10
11 #include <mcld/Environment.h>
12 #include <mcld/Module.h>
13 #include <mcld/InputTree.h>
14 #include <mcld/IRBuilder.h>
15 #include <mcld/Linker.h>
16 #include <mcld/LinkerConfig.h>
17
18 #include <mcld/Support/Path.h>
19
20 #include <llvm/Support/ELF.h>
21
22 using namespace mcld;
23 using namespace mcld::test;
24 using namespace mcld::sys::fs;
25
26
27 // Constructor can do set-up work for all test here.
LinkerTest()28 LinkerTest::LinkerTest()
29 {
30 }
31
32 // Destructor can do clean-up work that doesn't throw exceptions here.
~LinkerTest()33 LinkerTest::~LinkerTest()
34 {
35 }
36
37 // SetUp() will be called immediately before each test.
SetUp()38 void LinkerTest::SetUp()
39 {
40 }
41
42 // TearDown() will be called immediately after each test.
TearDown()43 void LinkerTest::TearDown()
44 {
45 }
46
47 //===----------------------------------------------------------------------===//
48 // Testcases
49 //===----------------------------------------------------------------------===//
TEST_F(LinkerTest,set_up_n_clean_up)50 TEST_F( LinkerTest, set_up_n_clean_up) {
51
52 Initialize();
53 LinkerConfig config("arm-none-linux-gnueabi");
54 LinkerScript script;
55 Module module("test", script);
56 config.setCodeGenType(LinkerConfig::DynObj);
57
58 Linker linker;
59 linker.emulate(script, config);
60
61 IRBuilder builder(module, config);
62 // create inputs here
63 // builder.CreateInput("./test.o");
64
65 if (linker.link(module, builder))
66 linker.emit("./test.so");
67
68 Finalize();
69 }
70
71 // %MCLinker --shared -soname=libplasma.so -Bsymbolic
72 // -mtriple="armv7-none-linux-gnueabi"
73 // -L=%p/../../../libs/ARM/Android/android-14
74 // %p/../../../libs/ARM/Android/android-14/crtbegin_so.o
75 // %p/plasma.o
76 // -lm -llog -ljnigraphics -lc
77 // %p/../../../libs/ARM/Android/android-14/crtend_so.o
78 // -o libplasma.so
TEST_F(LinkerTest,plasma)79 TEST_F( LinkerTest, plasma) {
80
81 Initialize();
82 Linker linker;
83 LinkerScript script;
84
85 ///< --mtriple="armv7-none-linux-gnueabi"
86 LinkerConfig config("armv7-none-linux-gnueabi");
87
88 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
89 Path search_dir(TOPDIR);
90 search_dir.append("test/libs/ARM/Android/android-14");
91 script.directories().insert(search_dir);
92
93 /// To configure linker before setting options. Linker::config sets up
94 /// default target-dependent configuration to LinkerConfig.
95 linker.emulate(script, config);
96
97 config.setCodeGenType(LinkerConfig::DynObj); ///< --shared
98 config.options().setSOName("libplasma.so"); ///< --soname=libplasma.so
99 config.options().setBsymbolic(); ///< -Bsymbolic
100
101 Module module("libplasma.so", script);
102 IRBuilder builder(module, config);
103
104 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o
105 Path crtbegin(search_dir);
106 crtbegin.append("crtbegin_so.o");
107 builder.ReadInput("crtbegin", crtbegin);
108
109 /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o
110 Path plasma(TOPDIR);
111 plasma.append("test/Android/Plasma/ARM/plasma.o");
112 builder.ReadInput("plasma", plasma);
113
114 // -lm -llog -ljnigraphics -lc
115 builder.ReadInput("m");
116 builder.ReadInput("log");
117 builder.ReadInput("jnigraphics");
118 builder.ReadInput("c");
119
120 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o
121 Path crtend(search_dir);
122 crtend.append("crtend_so.o");
123 builder.ReadInput("crtend", crtend);
124
125 if (linker.link(module, builder)) {
126 linker.emit("libplasma.so"); ///< -o libplasma.so
127 }
128
129 Finalize();
130 }
131
132 // The outputs generated without -Bsymbolic usually have more relocation
133 // entries than the outputs generated with -Bsymbolic. This testcase generates
134 // output with -Bsymbolic first, then generate the same output without -Bsymbolic.
135 // By this way, we can make sure symbols and relocations are cleaned between
136 // two linkings.
TEST_F(LinkerTest,plasma_twice)137 TEST_F( LinkerTest, plasma_twice) {
138
139 Initialize();
140 Linker linker;
141
142 ///< --mtriple="armv7-none-linux-gnueabi"
143 LinkerConfig config1("armv7-none-linux-gnueabi");
144
145 LinkerScript script1;
146 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
147 Path search_dir(TOPDIR);
148 search_dir.append("test/libs/ARM/Android/android-14");
149 script1.directories().insert(search_dir);
150
151 /// To configure linker before setting options. Linker::config sets up
152 /// default target-dependent configuration to LinkerConfig.
153 linker.emulate(script1, config1);
154
155 config1.setCodeGenType(LinkerConfig::DynObj); ///< --shared
156 config1.options().setSOName("libplasma.once.so"); ///< --soname=libplasma.twice.so
157 config1.options().setBsymbolic(false); ///< -Bsymbolic
158
159 Module module1("libplasma.once.so", script1);
160 IRBuilder builder1(module1, config1);
161
162 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o
163 Path crtbegin(search_dir);
164 crtbegin.append("crtbegin_so.o");
165 builder1.ReadInput("crtbegin", crtbegin);
166
167 /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o
168 Path plasma(TOPDIR);
169 plasma.append("test/Android/Plasma/ARM/plasma.o");
170 builder1.ReadInput("plasma", plasma);
171
172 // -lm -llog -ljnigraphics -lc
173 builder1.ReadInput("m");
174 builder1.ReadInput("log");
175 builder1.ReadInput("jnigraphics");
176 builder1.ReadInput("c");
177
178 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o
179 Path crtend(search_dir);
180 crtend.append("crtend_so.o");
181 builder1.ReadInput("crtend", crtend);
182
183 if (linker.link(module1, builder1)) {
184 linker.emit("libplasma.once.so"); ///< -o libplasma.so
185 }
186
187 Finalize();
188
189 linker.reset();
190
191 Initialize();
192
193 ///< --mtriple="armv7-none-linux-gnueabi"
194 LinkerConfig config2("armv7-none-linux-gnueabi");
195
196 LinkerScript script2;
197 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
198 script2.directories().insert(search_dir);
199
200 /// To configure linker before setting options. Linker::config sets up
201 /// default target-dependent configuration to LinkerConfig.
202 linker.emulate(script2, config2);
203
204 config2.setCodeGenType(LinkerConfig::DynObj); ///< --shared
205 config2.options().setSOName("libplasma.twice.so"); ///< --soname=libplasma.twice.exe
206 config2.options().setBsymbolic(); ///< -Bsymbolic
207
208 Module module2("libplasma.so", script2);
209 IRBuilder builder2(module2, config2);
210
211 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o
212 builder2.ReadInput("crtbegin", crtbegin);
213
214 /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o
215 builder2.ReadInput("plasma", plasma);
216
217 // -lm -llog -ljnigraphics -lc
218 builder2.ReadInput("m");
219 builder2.ReadInput("log");
220 builder2.ReadInput("jnigraphics");
221 builder2.ReadInput("c");
222
223 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o
224 builder2.ReadInput("crtend", crtend);
225
226 if (linker.link(module2, builder2)) {
227 linker.emit("libplasma.twice.so"); ///< -o libplasma.exe
228 }
229
230 Finalize();
231 }
232
233 // This testcase put IRBuilder in the heap
TEST_F(LinkerTest,plasma_twice_irbuilder_heap)234 TEST_F( LinkerTest, plasma_twice_irbuilder_heap) {
235
236 Initialize();
237 Linker linker;
238
239 ///< --mtriple="armv7-none-linux-gnueabi"
240 LinkerConfig config1("armv7-none-linux-gnueabi");
241
242 LinkerScript script1;
243 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
244 Path search_dir(TOPDIR);
245 search_dir.append("test/libs/ARM/Android/android-14");
246 script1.directories().insert(search_dir);
247
248 /// To configure linker before setting options. Linker::config sets up
249 /// default target-dependent configuration to LinkerConfig.
250 linker.emulate(script1, config1);
251
252 config1.setCodeGenType(LinkerConfig::DynObj); ///< --shared
253 config1.options().setSOName("libplasma.once.so"); ///< --soname=libplasma.twice.so
254 config1.options().setBsymbolic(false); ///< -Bsymbolic
255
256 Module module1("libplasma.once.so", script1);
257 IRBuilder *builder1 = new IRBuilder(module1, config1);
258
259 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o
260 Path crtbegin(search_dir);
261 crtbegin.append("crtbegin_so.o");
262 builder1->ReadInput("crtbegin", crtbegin);
263
264 /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o
265 Path plasma(TOPDIR);
266 plasma.append("test/Android/Plasma/ARM/plasma.o");
267 builder1->ReadInput("plasma", plasma);
268
269 // -lm -llog -ljnigraphics -lc
270 builder1->ReadInput("m");
271 builder1->ReadInput("log");
272 builder1->ReadInput("jnigraphics");
273 builder1->ReadInput("c");
274
275 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o
276 Path crtend(search_dir);
277 crtend.append("crtend_so.o");
278 builder1->ReadInput("crtend", crtend);
279
280 if (linker.link(module1, *builder1)) {
281 linker.emit("libplasma.once.so"); ///< -o libplasma.so
282 }
283
284 // Can not delete builder until emit the output. Dynamic string table
285 // needs the file name of the input files, and the inputs' life is
286 // controlled by IRBuilder
287 delete builder1;
288
289 Finalize();
290
291 linker.reset();
292
293 Initialize();
294
295 ///< --mtriple="armv7-none-linux-gnueabi"
296 LinkerConfig config2("armv7-none-linux-gnueabi");
297
298 LinkerScript script2;
299 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
300 script2.directories().insert(search_dir);
301
302 /// To configure linker before setting options. Linker::config sets up
303 /// default target-dependent configuration to LinkerConfig.
304 linker.emulate(script2, config2);
305
306 config2.setCodeGenType(LinkerConfig::DynObj); ///< --shared
307 config2.options().setSOName("libplasma.twice.so"); ///< --soname=libplasma.twice.exe
308 config2.options().setBsymbolic(); ///< -Bsymbolic
309
310 Module module2("libplasma.so", script2);
311 IRBuilder* builder2 = new IRBuilder(module2, config2);
312
313 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o
314 builder2->ReadInput("crtbegin", crtbegin);
315
316 /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o
317 builder2->ReadInput("plasma", plasma);
318
319 // -lm -llog -ljnigraphics -lc
320 builder2->ReadInput("m");
321 builder2->ReadInput("log");
322 builder2->ReadInput("jnigraphics");
323 builder2->ReadInput("c");
324
325 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o
326 builder2->ReadInput("crtend", crtend);
327
328 if (linker.link(module2, *builder2)) {
329 linker.emit("libplasma.twice.so"); ///< -o libplasma.exe
330 }
331
332 delete builder2;
333 Finalize();
334 }
335
336 // %MCLinker --shared -soname=libgotplt.so -mtriple arm-none-linux-gnueabi
337 // gotplt.o -o libgotplt.so
TEST_F(LinkerTest,plasma_object)338 TEST_F( LinkerTest, plasma_object) {
339
340 Initialize();
341 Linker linker;
342
343 ///< --mtriple="armv7-none-linux-gnueabi"
344 LinkerConfig config("armv7-none-linux-gnueabi");
345 LinkerScript script;
346
347 /// To configure linker before setting options. Linker::config sets up
348 /// default target-dependent configuration to LinkerConfig.
349 linker.emulate(script, config);
350
351 config.setCodeGenType(LinkerConfig::DynObj); ///< --shared
352 config.options().setSOName("libgotplt.so"); ///< --soname=libgotplt.so
353
354 Module module(script);
355 IRBuilder builder(module, config);
356
357 Path gotplt_o(TOPDIR);
358 gotplt_o.append("test/PLT/gotplt.o");
359 Input* input = builder.CreateInput("gotplt.o", gotplt_o, Input::Object);
360
361 /// Sections
362 /// [ 0] NULL 00000000 000000 000000 00 0 0 0
363 builder.CreateELFHeader(*input,
364 "",
365 LDFileFormat::Null,
366 llvm::ELF::SHT_NULL,
367 0x0);
368
369 /// [ 1] .text PROGBITS 00000000 000034 000010 00 AX 0 0 4
370 LDSection* text = builder.CreateELFHeader(*input,
371 ".text",
372 llvm::ELF::SHT_PROGBITS,
373 llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
374 4);
375
376 SectionData* text_data = builder.CreateSectionData(*text);
377 static uint8_t text_content[] = { 0x00, 0x48, 0x2d, 0xe9,
378 0xfe, 0xff, 0xff, 0xeb,
379 0x00, 0x48, 0xbd, 0xe8,
380 0x0e, 0xf0, 0xa0, 0xe1 };
381 Fragment* text_frag = builder.CreateRegion(text_content, 0x10);
382 builder.AppendFragment(*text_frag, *text_data);
383
384 /// [ 2] .rel.text REL 00000000 0002ac 000008 08 7 1 4
385 LDSection* rel_text = builder.CreateELFHeader(*input,
386 ".rel.text",
387 llvm::ELF::SHT_REL,
388 0x0, 4);
389 rel_text->setLink(text);
390 builder.CreateRelocData(*rel_text);
391
392 /// [ 3] .data PROGBITS 00000000 000044 000000 00 WA 0 0 4
393 LDSection* data = builder.CreateELFHeader(*input,
394 ".data",
395 llvm::ELF::SHT_PROGBITS,
396 llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
397 4);
398
399 /// [ 4] .bss NOBITS 00000000 000044 000000 00 WA 0 0 4
400 LDSection* bss = builder.CreateELFHeader(*input,
401 ".bss",
402 llvm::ELF::SHT_NOBITS,
403 llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
404 4);
405 builder.CreateBSS(*bss);
406
407 /// [ 5] .ARM.attributes ARM_ATTRIBUTES 00000000 000044 000020 00 0 0 1
408 LDSection* attr = builder.CreateELFHeader(*input,
409 ".ARM.attributes",
410 llvm::ELF::SHT_ARM_ATTRIBUTES,
411 0x0,
412 1);
413
414 SectionData* attr_data = builder.CreateSectionData(*attr);
415 static uint8_t attr_content[] = {
416 0x41, 0x1f, 0x00, 0x00,
417 0x00, 0x61, 0x65, 0x61,
418 0x62, 0x69, 0x00, 0x01,
419 0x15, 0x00, 0x00, 0x00,
420 0x06, 0x02, 0x08, 0x01,
421 0x09, 0x01, 0x14, 0x01,
422 0x15, 0x01, 0x17, 0x03,
423 0x18, 0x01, 0x19, 0x01 };
424 Fragment* attr_frag = builder.CreateRegion(attr_content, 0x20);
425 builder.AppendFragment(*attr_frag, *attr_data);
426
427 /// Symbols
428 /// 1: 00000000 0 FILE LOCAL DEFAULT ABS Output/gotplt.bc
429 builder.AddSymbol(*input,
430 "Output/gotplt.bc", ResolveInfo::File,
431 ResolveInfo::Define, ResolveInfo::Local, 0);
432 /// 2: 00000000 0 SECTION LOCAL DEFAULT 1
433 builder.AddSymbol(*input,
434 ".text", ResolveInfo::Section,
435 ResolveInfo::Define, ResolveInfo::Local, 0, 0x0, text);
436 /// 3: 00000000 0 SECTION LOCAL DEFAULT 3
437 builder.AddSymbol(*input,
438 ".data", ResolveInfo::Section,
439 ResolveInfo::Define, ResolveInfo::Local, 0, 0x0, data);
440 /// 4: 00000000 0 SECTION LOCAL DEFAULT 4
441 builder.AddSymbol(*input,
442 ".bss", ResolveInfo::Section,
443 ResolveInfo::Define, ResolveInfo::Local, 0, 0x0, bss);
444 /// 5: 00000000 0 SECTION LOCAL DEFAULT 5
445 builder.AddSymbol(*input,
446 ".ARM.attributes", ResolveInfo::Section,
447 ResolveInfo::Define, ResolveInfo::Local, 0, 0x0, attr);
448 /// 6: 00000000 16 FUNC GLOBAL DEFAULT 1 _Z1fv
449 builder.AddSymbol(*input,
450 "_Z1fv", ResolveInfo::Function,
451 ResolveInfo::Define, ResolveInfo::Global,
452 16,
453 0x0,
454 text);
455
456 /// 7: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Z1gv
457 LDSymbol* z1gv = builder.AddSymbol(*input,
458 "_Z1gv",
459 ResolveInfo::NoType,
460 ResolveInfo::Undefined,
461 ResolveInfo::Global,
462 0);
463
464 /// Relocations
465 /// Offset Info Type Sym.Value Sym. Name
466 /// 00000004 0000071b R_ARM_PLT32 00000000 _Z1gv
467 builder.AddRelocation(*rel_text, llvm::ELF::R_ARM_PLT32, *z1gv, 0x4);
468
469 if (linker.link(module, builder)) {
470 linker.emit("libgotplt.so"); ///< -o libgotplt.so
471 }
472
473 Finalize();
474 }
475