LinkerTest.cpp revision 551ae4ebd3e9d137ea668fb83ae4a55b8cfba451
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
23using namespace mcld;
24using namespace mcld::test;
25using namespace mcld::sys::fs;
26
27
28// Constructor can do set-up work for all test here.
29LinkerTest::LinkerTest()
30{
31}
32
33// Destructor can do clean-up work that doesn't throw exceptions here.
34LinkerTest::~LinkerTest()
35{
36}
37
38// SetUp() will be called immediately before each test.
39void LinkerTest::SetUp()
40{
41}
42
43// TearDown() will be called immediately after each test.
44void LinkerTest::TearDown()
45{
46}
47
48//===----------------------------------------------------------------------===//
49// Testcases
50//===----------------------------------------------------------------------===//
51TEST_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
80TEST_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.
138TEST_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
235TEST_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
339TEST_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