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