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