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  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
79TEST_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.
137TEST_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
234TEST_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
338TEST_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