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