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