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// Constructor can do set-up work for all test here.
28LinkerTest::LinkerTest() {
29}
30
31// Destructor can do clean-up work that doesn't throw exceptions here.
32LinkerTest::~LinkerTest() {
33}
34
35// SetUp() will be called immediately before each test.
36void LinkerTest::SetUp() {
37}
38
39// TearDown() will be called immediately after each test.
40void LinkerTest::TearDown() {
41}
42
43//===----------------------------------------------------------------------===//
44// Testcases
45//===----------------------------------------------------------------------===//
46TEST_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
74TEST_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.
132TEST_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
230TEST_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
335TEST_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