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