• 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 #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