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