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