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