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