LinkerTest.cpp revision 22add6ff3426df1a85089fe6a6e1597ee3b6f300
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  /// To configure linker before setting options. Linker::config sets up
88  /// default target-dependent configuration to LinkerConfig.
89  linker.config(config);
90
91  config.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
92  config.options().setSOName("libplasma.so");   ///< --soname=libplasma.so
93  config.options().setBsymbolic();              ///< -Bsymbolic
94
95  /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
96  Path search_dir(TOPDIR);
97  search_dir.append("test/libs/ARM/Android/android-14");
98  config.options().directories().insert(search_dir);
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  /// To configure linker before setting options. Linker::config sets up
145  /// default target-dependent configuration to LinkerConfig.
146  linker.config(config1);
147
148  config1.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
149  config1.options().setSOName("libplasma.once.so");   ///< --soname=libplasma.twice.so
150  config1.options().setBsymbolic(false);              ///< -Bsymbolic
151
152  /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
153  Path search_dir(TOPDIR);
154  search_dir.append("test/libs/ARM/Android/android-14");
155  config1.options().directories().insert(search_dir);
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  /// To configure linker before setting options. Linker::config sets up
195  /// default target-dependent configuration to LinkerConfig.
196  linker.config(config2);
197
198  config2.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
199  config2.options().setSOName("libplasma.twice.so");   ///< --soname=libplasma.twice.exe
200  config2.options().setBsymbolic();              ///< -Bsymbolic
201
202  /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
203  config2.options().directories().insert(search_dir);
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  /// To configure linker before setting options. Linker::config sets up
240  /// default target-dependent configuration to LinkerConfig.
241  linker.config(config1);
242
243  config1.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
244  config1.options().setSOName("libplasma.once.so");   ///< --soname=libplasma.twice.so
245  config1.options().setBsymbolic(false);              ///< -Bsymbolic
246
247  /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
248  Path search_dir(TOPDIR);
249  search_dir.append("test/libs/ARM/Android/android-14");
250  config1.options().directories().insert(search_dir);
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  /// To configure linker before setting options. Linker::config sets up
295  /// default target-dependent configuration to LinkerConfig.
296  linker.config(config2);
297
298  config2.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
299  config2.options().setSOName("libplasma.twice.so");   ///< --soname=libplasma.twice.exe
300  config2.options().setBsymbolic();              ///< -Bsymbolic
301
302  /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
303  config2.options().directories().insert(search_dir);
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  /// [ 0]                   NULL            00000000 000000 000000 00      0   0  0
356  builder.CreateELFHeader(*input,
357                          "",
358                          LDFileFormat::Null,
359                          llvm::ELF::SHT_NULL,
360                          0x0);
361
362  /// [ 1] .text             PROGBITS        00000000 000034 000010 00  AX  0   0  4
363  LDSection* text = builder.CreateELFHeader(*input,
364                              ".text",
365                              llvm::ELF::SHT_PROGBITS,
366                              llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
367                              4);
368
369  SectionData* text_data = builder.CreateSectionData(*text);
370  static uint8_t text_content[] = { 0x00, 0x48, 0x2d, 0xe9,
371                                    0xfe, 0xff, 0xff, 0xeb,
372                                    0x00, 0x48, 0xbd, 0xe8,
373                                    0x0e, 0xf0, 0xa0, 0xe1 };
374  Fragment* text_frag = builder.CreateRegion(text_content, 0x10);
375  builder.AppendFragment(*text_frag, *text_data);
376
377  // [ 3] .data             PROGBITS        00000000 000044 000000 00  WA  0   0  4
378  builder.CreateELFHeader(*input,
379                          ".data",
380                          llvm::ELF::SHT_PROGBITS,
381                          llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
382                          4);
383
384  // [ 4] .bss              NOBITS          00000000 000044 000000 00  WA  0   0  4
385  builder.CreateELFHeader(*input,
386                          ".bss",
387                          llvm::ELF::SHT_PROGBITS,
388                          llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
389                          4);
390  // [ 5] .ARM.attributes   ARM_ATTRIBUTES  00000000 000044 000020 00      0   0  1
391  LDSection* attr = builder.CreateELFHeader(*input,
392                              ".ARM.attributes",
393                              llvm::ELF::SHT_ARM_ATTRIBUTES,
394                              0x0,
395                              4);
396
397  SectionData* attr_data = builder.CreateSectionData(*attr);
398  static uint8_t attr_content[] = {
399                      0x41, 0x1f, 0x00, 0x00,
400                      0x00, 0x61, 0x65, 0x61,
401                      0x62, 0x69, 0x00, 0x01,
402                      0x15, 0x00, 0x00, 0x00,
403                      0x06, 0x02, 0x08, 0x01,
404                      0x09, 0x01, 0x14, 0x01,
405                      0x15, 0x01, 0x17, 0x03,
406                      0x18, 0x01, 0x19, 0x01 };
407  Fragment* attr_frag = builder.CreateRegion(attr_content, 0x20);
408  builder.AppendFragment(*attr_frag, *attr_data);
409
410  if (linker.link(module, builder)) {
411    linker.emit("libgotplt.so"); ///< -o libgotplt.so
412  }
413
414  Finalize();
415}
416