• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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