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 // Constructor can do set-up work for all test here.
     28 LinkerTest::LinkerTest() {
     29 }
     30 
     31 // Destructor can do clean-up work that doesn't throw exceptions here.
     32 LinkerTest::~LinkerTest() {
     33 }
     34 
     35 // SetUp() will be called immediately before each test.
     36 void LinkerTest::SetUp() {
     37 }
     38 
     39 // TearDown() will be called immediately after each test.
     40 void LinkerTest::TearDown() {
     41 }
     42 
     43 //===----------------------------------------------------------------------===//
     44 // Testcases
     45 //===----------------------------------------------------------------------===//
     46 TEST_F(LinkerTest, set_up_n_clean_up) {
     47   Initialize();
     48   LinkerConfig config("arm-none-linux-gnueabi");
     49   LinkerScript script;
     50   Module module("test", script);
     51   config.setCodeGenType(LinkerConfig::DynObj);
     52 
     53   Linker linker;
     54   linker.emulate(script, config);
     55 
     56   IRBuilder builder(module, config);
     57   // create inputs here
     58   //   builder.CreateInput("./test.o");
     59 
     60   if (linker.link(module, builder))
     61     linker.emit(module, "./test.so");
     62 
     63   Finalize();
     64 }
     65 
     66 // %MCLinker --shared -soname=libplasma.so -Bsymbolic
     67 // -mtriple="armv7-none-linux-gnueabi"
     68 // -L=%p/../../../libs/ARM/Android/android-14
     69 // %p/../../../libs/ARM/Android/android-14/crtbegin_so.o
     70 // %p/plasma.o
     71 // -lm -llog -ljnigraphics -lc
     72 // %p/../../../libs/ARM/Android/android-14/crtend_so.o
     73 // -o libplasma.so
     74 TEST_F(LinkerTest, plasma) {
     75   Initialize();
     76   Linker linker;
     77   LinkerScript script;
     78 
     79   ///< --mtriple="armv7-none-linux-gnueabi"
     80   LinkerConfig config("armv7-none-linux-gnueabi");
     81 
     82   /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
     83   Path search_dir(TOPDIR);
     84   search_dir.append("test/libs/ARM/Android/android-14");
     85   script.directories().insert(search_dir);
     86 
     87   /// To configure linker before setting options. Linker::config sets up
     88   /// default target-dependent configuration to LinkerConfig.
     89   linker.emulate(script, config);
     90 
     91   config.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
     92   config.options().setSOName("libplasma.so");   ///< --soname=libplasma.so
     93   config.options().setBsymbolic();              ///< -Bsymbolic
     94 
     95   Module module("libplasma.so", script);
     96   IRBuilder builder(module, config);
     97 
     98   /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o
     99   Path crtbegin(search_dir);
    100   crtbegin.append("crtbegin_so.o");
    101   builder.ReadInput("crtbegin", crtbegin);
    102 
    103   /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o
    104   Path plasma(TOPDIR);
    105   plasma.append("test/Android/Plasma/ARM/plasma.o");
    106   builder.ReadInput("plasma", plasma);
    107 
    108   // -lm -llog -ljnigraphics -lc
    109   builder.ReadInput("m");
    110   builder.ReadInput("log");
    111   builder.ReadInput("jnigraphics");
    112   builder.ReadInput("c");
    113 
    114   /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o
    115   Path crtend(search_dir);
    116   crtend.append("crtend_so.o");
    117   builder.ReadInput("crtend", crtend);
    118 
    119   if (linker.link(module, builder)) {
    120     linker.emit(module, "libplasma.so");  ///< -o libplasma.so
    121   }
    122 
    123   Finalize();
    124 }
    125 
    126 // The outputs generated without -Bsymbolic usually have more relocation
    127 // entries than the outputs generated with -Bsymbolic. This testcase generates
    128 // output with -Bsymbolic first, then generate the same output without
    129 // -Bsymbolic.
    130 // By this way, we can make sure symbols and relocations are cleaned between
    131 // two linkings.
    132 TEST_F(LinkerTest, plasma_twice) {
    133   Initialize();
    134   Linker linker;
    135 
    136   ///< --mtriple="armv7-none-linux-gnueabi"
    137   LinkerConfig config1("armv7-none-linux-gnueabi");
    138 
    139   LinkerScript script1;
    140   /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
    141   Path search_dir(TOPDIR);
    142   search_dir.append("test/libs/ARM/Android/android-14");
    143   script1.directories().insert(search_dir);
    144 
    145   /// To configure linker before setting options. Linker::config sets up
    146   /// default target-dependent configuration to LinkerConfig.
    147   linker.emulate(script1, config1);
    148 
    149   config1.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
    150   config1.options().setSOName(
    151       "libplasma.once.so");               ///< --soname=libplasma.twice.so
    152   config1.options().setBsymbolic(false);  ///< -Bsymbolic
    153 
    154   Module module1("libplasma.once.so", script1);
    155   IRBuilder builder1(module1, config1);
    156 
    157   /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o
    158   Path crtbegin(search_dir);
    159   crtbegin.append("crtbegin_so.o");
    160   builder1.ReadInput("crtbegin", crtbegin);
    161 
    162   /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o
    163   Path plasma(TOPDIR);
    164   plasma.append("test/Android/Plasma/ARM/plasma.o");
    165   builder1.ReadInput("plasma", plasma);
    166 
    167   // -lm -llog -ljnigraphics -lc
    168   builder1.ReadInput("m");
    169   builder1.ReadInput("log");
    170   builder1.ReadInput("jnigraphics");
    171   builder1.ReadInput("c");
    172 
    173   /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o
    174   Path crtend(search_dir);
    175   crtend.append("crtend_so.o");
    176   builder1.ReadInput("crtend", crtend);
    177 
    178   if (linker.link(module1, builder1)) {
    179     linker.emit(module1, "libplasma.once.so");  ///< -o libplasma.so
    180   }
    181 
    182   Finalize();
    183 
    184   linker.reset();
    185 
    186   Initialize();
    187 
    188   ///< --mtriple="armv7-none-linux-gnueabi"
    189   LinkerConfig config2("armv7-none-linux-gnueabi");
    190 
    191   LinkerScript script2;
    192   /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
    193   script2.directories().insert(search_dir);
    194 
    195   /// To configure linker before setting options. Linker::config sets up
    196   /// default target-dependent configuration to LinkerConfig.
    197   linker.emulate(script2, config2);
    198 
    199   config2.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
    200   config2.options().setSOName(
    201       "libplasma.twice.so");         ///< --soname=libplasma.twice.exe
    202   config2.options().setBsymbolic();  ///< -Bsymbolic
    203 
    204   Module module2("libplasma.so", script2);
    205   IRBuilder builder2(module2, config2);
    206 
    207   /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o
    208   builder2.ReadInput("crtbegin", crtbegin);
    209 
    210   /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o
    211   builder2.ReadInput("plasma", plasma);
    212 
    213   // -lm -llog -ljnigraphics -lc
    214   builder2.ReadInput("m");
    215   builder2.ReadInput("log");
    216   builder2.ReadInput("jnigraphics");
    217   builder2.ReadInput("c");
    218 
    219   /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o
    220   builder2.ReadInput("crtend", crtend);
    221 
    222   if (linker.link(module2, builder2)) {
    223     linker.emit(module2, "libplasma.twice.so");  ///< -o libplasma.exe
    224   }
    225 
    226   Finalize();
    227 }
    228 
    229 // This testcase put IRBuilder in the heap
    230 TEST_F(LinkerTest, plasma_twice_irbuilder_heap) {
    231   Initialize();
    232   Linker linker;
    233 
    234   ///< --mtriple="armv7-none-linux-gnueabi"
    235   LinkerConfig config1("armv7-none-linux-gnueabi");
    236 
    237   LinkerScript script1;
    238   /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
    239   Path search_dir(TOPDIR);
    240   search_dir.append("test/libs/ARM/Android/android-14");
    241   script1.directories().insert(search_dir);
    242 
    243   /// To configure linker before setting options. Linker::config sets up
    244   /// default target-dependent configuration to LinkerConfig.
    245   linker.emulate(script1, config1);
    246 
    247   config1.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
    248   config1.options().setSOName(
    249       "libplasma.once.so");               ///< --soname=libplasma.twice.so
    250   config1.options().setBsymbolic(false);  ///< -Bsymbolic
    251 
    252   Module module1("libplasma.once.so", script1);
    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(module1, "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   LinkerScript script2;
    295   /// -L=${TOPDIR}/test/libs/ARM/Android/android-14
    296   script2.directories().insert(search_dir);
    297 
    298   /// To configure linker before setting options. Linker::config sets up
    299   /// default target-dependent configuration to LinkerConfig.
    300   linker.emulate(script2, config2);
    301 
    302   config2.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
    303   config2.options().setSOName(
    304       "libplasma.twice.so");         ///< --soname=libplasma.twice.exe
    305   config2.options().setBsymbolic();  ///< -Bsymbolic
    306 
    307   Module module2("libplasma.so", script2);
    308   IRBuilder* builder2 = new IRBuilder(module2, config2);
    309 
    310   /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o
    311   builder2->ReadInput("crtbegin", crtbegin);
    312 
    313   /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o
    314   builder2->ReadInput("plasma", plasma);
    315 
    316   // -lm -llog -ljnigraphics -lc
    317   builder2->ReadInput("m");
    318   builder2->ReadInput("log");
    319   builder2->ReadInput("jnigraphics");
    320   builder2->ReadInput("c");
    321 
    322   /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o
    323   builder2->ReadInput("crtend", crtend);
    324 
    325   if (linker.link(module2, *builder2)) {
    326     linker.emit(module2, "libplasma.twice.so");  ///< -o libplasma.exe
    327   }
    328 
    329   delete builder2;
    330   Finalize();
    331 }
    332 
    333 // %MCLinker --shared -soname=libgotplt.so -mtriple arm-none-linux-gnueabi
    334 // gotplt.o -o libgotplt.so
    335 TEST_F(LinkerTest, plasma_object) {
    336   Initialize();
    337   Linker linker;
    338 
    339   ///< --mtriple="armv7-none-linux-gnueabi"
    340   LinkerConfig config("armv7-none-linux-gnueabi");
    341   LinkerScript script;
    342 
    343   /// To configure linker before setting options. Linker::config sets up
    344   /// default target-dependent configuration to LinkerConfig.
    345   linker.emulate(script, config);
    346 
    347   config.setCodeGenType(LinkerConfig::DynObj);  ///< --shared
    348   config.options().setSOName("libgotplt.so");   ///< --soname=libgotplt.so
    349 
    350   Module module(script);
    351   IRBuilder builder(module, config);
    352 
    353   Path gotplt_o(TOPDIR);
    354   gotplt_o.append("test/PLT/gotplt.o");
    355   Input* input = builder.CreateInput("gotplt.o", gotplt_o, Input::Object);
    356 
    357   /// Sections
    358   /// [ 0]                   NULL            00000000 000000 000000 00      0
    359   /// 0  0
    360   builder.CreateELFHeader(
    361       *input, "", LDFileFormat::Null, llvm::ELF::SHT_NULL, 0x0);
    362 
    363   /// [ 1] .text             PROGBITS        00000000 000034 000010 00  AX  0
    364   /// 0  4
    365   LDSection* text =
    366       builder.CreateELFHeader(*input,
    367                               ".text",
    368                               llvm::ELF::SHT_PROGBITS,
    369                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
    370                               4);
    371 
    372   SectionData* text_data = builder.CreateSectionData(*text);
    373   static uint8_t text_content[] = {
    374       0x00, 0x48, 0x2d, 0xe9,
    375       0xfe, 0xff, 0xff, 0xeb,
    376       0x00, 0x48, 0xbd, 0xe8,
    377       0x0e, 0xf0, 0xa0, 0xe1
    378   };
    379 
    380   Fragment* text_frag = builder.CreateRegion(text_content, 0x10);
    381   builder.AppendFragment(*text_frag, *text_data);
    382 
    383   /// [ 2] .rel.text         REL             00000000 0002ac 000008 08      7
    384   /// 1  4
    385   LDSection* rel_text =
    386       builder.CreateELFHeader(*input, ".rel.text", llvm::ELF::SHT_REL, 0x0, 4);
    387   rel_text->setLink(text);
    388   builder.CreateRelocData(*rel_text);
    389 
    390   /// [ 3] .data             PROGBITS        00000000 000044 000000 00  WA  0
    391   /// 0  4
    392   LDSection* data =
    393       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
    400   /// 0  4
    401   LDSection* bss =
    402       builder.CreateELFHeader(*input,
    403                               ".bss",
    404                               llvm::ELF::SHT_NOBITS,
    405                               llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE,
    406                               4);
    407   builder.CreateBSS(*bss);
    408 
    409   /// [ 5] .ARM.attributes   ARM_ATTRIBUTES  00000000 000044 000020 00      0
    410   /// 0  1
    411   LDSection* attr = builder.CreateELFHeader(
    412       *input, ".ARM.attributes", llvm::ELF::SHT_ARM_ATTRIBUTES, 0x0, 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   };
    425 
    426   Fragment* attr_frag = builder.CreateRegion(attr_content, 0x20);
    427   builder.AppendFragment(*attr_frag, *attr_data);
    428 
    429   /// Symbols
    430   /// 1: 00000000     0 FILE    LOCAL  DEFAULT  ABS Output/gotplt.bc
    431   builder.AddSymbol(*input,
    432                     "Output/gotplt.bc",
    433                     ResolveInfo::File,
    434                     ResolveInfo::Define,
    435                     ResolveInfo::Local,
    436                     0);
    437   /// 2: 00000000     0 SECTION LOCAL  DEFAULT    1
    438   builder.AddSymbol(*input,
    439                     ".text",
    440                     ResolveInfo::Section,
    441                     ResolveInfo::Define,
    442                     ResolveInfo::Local,
    443                     0,
    444                     0x0,
    445                     text);
    446   /// 3: 00000000     0 SECTION LOCAL  DEFAULT    3
    447   builder.AddSymbol(*input,
    448                     ".data",
    449                     ResolveInfo::Section,
    450                     ResolveInfo::Define,
    451                     ResolveInfo::Local,
    452                     0,
    453                     0x0,
    454                     data);
    455   /// 4: 00000000     0 SECTION LOCAL  DEFAULT    4
    456   builder.AddSymbol(*input,
    457                     ".bss",
    458                     ResolveInfo::Section,
    459                     ResolveInfo::Define,
    460                     ResolveInfo::Local,
    461                     0,
    462                     0x0,
    463                     bss);
    464   /// 5: 00000000     0 SECTION LOCAL  DEFAULT    5
    465   builder.AddSymbol(*input,
    466                     ".ARM.attributes",
    467                     ResolveInfo::Section,
    468                     ResolveInfo::Define,
    469                     ResolveInfo::Local,
    470                     0,
    471                     0x0,
    472                     attr);
    473   /// 6: 00000000    16 FUNC    GLOBAL DEFAULT    1 _Z1fv
    474   builder.AddSymbol(*input,
    475                     "_Z1fv",
    476                     ResolveInfo::Function,
    477                     ResolveInfo::Define,
    478                     ResolveInfo::Global,
    479                     16,
    480                     0x0,
    481                     text);
    482 
    483   /// 7: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND _Z1gv
    484   LDSymbol* z1gv = builder.AddSymbol(*input,
    485                                      "_Z1gv",
    486                                      ResolveInfo::NoType,
    487                                      ResolveInfo::Undefined,
    488                                      ResolveInfo::Global,
    489                                      0);
    490 
    491   /// Relocations
    492   /// Offset     Info    Type            Sym.Value  Sym. Name
    493   /// 00000004  0000071b R_ARM_PLT32       00000000   _Z1gv
    494   builder.AddRelocation(*rel_text, llvm::ELF::R_ARM_PLT32, *z1gv, 0x4);
    495 
    496   if (linker.link(module, builder)) {
    497     linker.emit(module, "libgotplt.so");  ///< -o libgotplt.so
    498   }
    499 
    500   Finalize();
    501 }
    502