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 
     18 #include <mcld/Support/Path.h>
     19 
     20 #include <llvm/Support/ELF.h>
     21 
     22 using namespace mcld;
     23 using namespace mcld::test;
     24 using namespace mcld::sys::fs;
     25 
     26 
     27 // Constructor can do set-up work for all test here.
     28 LinkerTest::LinkerTest()
     29 {
     30 }
     31 
     32 // Destructor can do clean-up work that doesn't throw exceptions here.
     33 LinkerTest::~LinkerTest()
     34 {
     35 }
     36 
     37 // SetUp() will be called immediately before each test.
     38 void LinkerTest::SetUp()
     39 {
     40 }
     41 
     42 // TearDown() will be called immediately after each test.
     43 void LinkerTest::TearDown()
     44 {
     45 }
     46 
     47 //===----------------------------------------------------------------------===//
     48 // Testcases
     49 //===----------------------------------------------------------------------===//
     50 TEST_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
     79 TEST_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.
    136 TEST_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
    231 TEST_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
    333 TEST_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