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 55 Module module("test"); 56 config.setCodeGenType(LinkerConfig::DynObj); 57 58 Linker linker; 59 linker.config(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 84 ///< --mtriple="armv7-none-linux-gnueabi" 85 LinkerConfig config("armv7-none-linux-gnueabi"); 86 87 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 88 Path search_dir(TOPDIR); 89 search_dir.append("test/libs/ARM/Android/android-14"); 90 config.options().directories().insert(search_dir); 91 92 /// To configure linker before setting options. Linker::config sets up 93 /// default target-dependent configuration to LinkerConfig. 94 linker.config(config); 95 96 config.setCodeGenType(LinkerConfig::DynObj); ///< --shared 97 config.options().setSOName("libplasma.so"); ///< --soname=libplasma.so 98 config.options().setBsymbolic(); ///< -Bsymbolic 99 100 Module module("libplasma.so"); 101 IRBuilder builder(module, config); 102 103 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o 104 Path crtbegin(search_dir); 105 crtbegin.append("crtbegin_so.o"); 106 builder.ReadInput("crtbegin", crtbegin); 107 108 /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o 109 Path plasma(TOPDIR); 110 plasma.append("test/Android/Plasma/ARM/plasma.o"); 111 builder.ReadInput("plasma", plasma); 112 113 // -lm -llog -ljnigraphics -lc 114 builder.ReadInput("m"); 115 builder.ReadInput("log"); 116 builder.ReadInput("jnigraphics"); 117 builder.ReadInput("c"); 118 119 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o 120 Path crtend(search_dir); 121 crtend.append("crtend_so.o"); 122 builder.ReadInput("crtend", crtend); 123 124 if (linker.link(module, builder)) { 125 linker.emit("libplasma.so"); ///< -o libplasma.so 126 } 127 128 Finalize(); 129 } 130 131 // The outputs generated without -Bsymbolic usually have more relocation 132 // entries than the outputs generated with -Bsymbolic. This testcase generates 133 // output with -Bsymbolic first, then generate the same output without -Bsymbolic. 134 // By this way, we can make sure symbols and relocations are cleaned between 135 // two linkings. 136 TEST_F( LinkerTest, plasma_twice) { 137 138 Initialize(); 139 Linker linker; 140 141 ///< --mtriple="armv7-none-linux-gnueabi" 142 LinkerConfig config1("armv7-none-linux-gnueabi"); 143 144 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 145 Path search_dir(TOPDIR); 146 search_dir.append("test/libs/ARM/Android/android-14"); 147 config1.options().directories().insert(search_dir); 148 149 /// To configure linker before setting options. Linker::config sets up 150 /// default target-dependent configuration to LinkerConfig. 151 linker.config(config1); 152 153 config1.setCodeGenType(LinkerConfig::DynObj); ///< --shared 154 config1.options().setSOName("libplasma.once.so"); ///< --soname=libplasma.twice.so 155 config1.options().setBsymbolic(false); ///< -Bsymbolic 156 157 Module module1("libplasma.once.so"); 158 IRBuilder builder1(module1, config1); 159 160 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o 161 Path crtbegin(search_dir); 162 crtbegin.append("crtbegin_so.o"); 163 builder1.ReadInput("crtbegin", crtbegin); 164 165 /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o 166 Path plasma(TOPDIR); 167 plasma.append("test/Android/Plasma/ARM/plasma.o"); 168 builder1.ReadInput("plasma", plasma); 169 170 // -lm -llog -ljnigraphics -lc 171 builder1.ReadInput("m"); 172 builder1.ReadInput("log"); 173 builder1.ReadInput("jnigraphics"); 174 builder1.ReadInput("c"); 175 176 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o 177 Path crtend(search_dir); 178 crtend.append("crtend_so.o"); 179 builder1.ReadInput("crtend", crtend); 180 181 if (linker.link(module1, builder1)) { 182 linker.emit("libplasma.once.so"); ///< -o libplasma.so 183 } 184 185 Finalize(); 186 187 linker.reset(); 188 189 Initialize(); 190 191 ///< --mtriple="armv7-none-linux-gnueabi" 192 LinkerConfig config2("armv7-none-linux-gnueabi"); 193 194 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 195 config2.options().directories().insert(search_dir); 196 197 /// To configure linker before setting options. Linker::config sets up 198 /// default target-dependent configuration to LinkerConfig. 199 linker.config(config2); 200 201 config2.setCodeGenType(LinkerConfig::DynObj); ///< --shared 202 config2.options().setSOName("libplasma.twice.so"); ///< --soname=libplasma.twice.exe 203 config2.options().setBsymbolic(); ///< -Bsymbolic 204 205 Module module2("libplasma.so"); 206 IRBuilder builder2(module2, config2); 207 208 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o 209 builder2.ReadInput("crtbegin", crtbegin); 210 211 /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o 212 builder2.ReadInput("plasma", plasma); 213 214 // -lm -llog -ljnigraphics -lc 215 builder2.ReadInput("m"); 216 builder2.ReadInput("log"); 217 builder2.ReadInput("jnigraphics"); 218 builder2.ReadInput("c"); 219 220 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o 221 builder2.ReadInput("crtend", crtend); 222 223 if (linker.link(module2, builder2)) { 224 linker.emit("libplasma.twice.so"); ///< -o libplasma.exe 225 } 226 227 Finalize(); 228 } 229 230 // This testcase put IRBuilder in the heap 231 TEST_F( LinkerTest, plasma_twice_irbuilder_heap) { 232 233 Initialize(); 234 Linker linker; 235 236 ///< --mtriple="armv7-none-linux-gnueabi" 237 LinkerConfig config1("armv7-none-linux-gnueabi"); 238 239 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 240 Path search_dir(TOPDIR); 241 search_dir.append("test/libs/ARM/Android/android-14"); 242 config1.options().directories().insert(search_dir); 243 244 /// To configure linker before setting options. Linker::config sets up 245 /// default target-dependent configuration to LinkerConfig. 246 linker.config(config1); 247 248 config1.setCodeGenType(LinkerConfig::DynObj); ///< --shared 249 config1.options().setSOName("libplasma.once.so"); ///< --soname=libplasma.twice.so 250 config1.options().setBsymbolic(false); ///< -Bsymbolic 251 252 Module module1("libplasma.once.so"); 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("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 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 295 config2.options().directories().insert(search_dir); 296 297 /// To configure linker before setting options. Linker::config sets up 298 /// default target-dependent configuration to LinkerConfig. 299 linker.config(config2); 300 301 config2.setCodeGenType(LinkerConfig::DynObj); ///< --shared 302 config2.options().setSOName("libplasma.twice.so"); ///< --soname=libplasma.twice.exe 303 config2.options().setBsymbolic(); ///< -Bsymbolic 304 305 Module module2("libplasma.so"); 306 IRBuilder* builder2 = new IRBuilder(module2, config2); 307 308 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtbegin_so.o 309 builder2->ReadInput("crtbegin", crtbegin); 310 311 /// ${TOPDIR}/test/Android/Plasma/ARM/plasma.o 312 builder2->ReadInput("plasma", plasma); 313 314 // -lm -llog -ljnigraphics -lc 315 builder2->ReadInput("m"); 316 builder2->ReadInput("log"); 317 builder2->ReadInput("jnigraphics"); 318 builder2->ReadInput("c"); 319 320 /// ${TOPDIR}/test/libs/ARM/Android/android-14/crtend_so.o 321 builder2->ReadInput("crtend", crtend); 322 323 if (linker.link(module2, *builder2)) { 324 linker.emit("libplasma.twice.so"); ///< -o libplasma.exe 325 } 326 327 delete builder2; 328 Finalize(); 329 } 330 331 // %MCLinker --shared -soname=libgotplt.so -mtriple arm-none-linux-gnueabi 332 // gotplt.o -o libgotplt.so 333 TEST_F( LinkerTest, plasma_object) { 334 335 Initialize(); 336 Linker linker; 337 338 ///< --mtriple="armv7-none-linux-gnueabi" 339 LinkerConfig config("armv7-none-linux-gnueabi"); 340 341 /// To configure linker before setting options. Linker::config sets up 342 /// default target-dependent configuration to LinkerConfig. 343 linker.config(config); 344 345 config.setCodeGenType(LinkerConfig::DynObj); ///< --shared 346 config.options().setSOName("libgotplt.so"); ///< --soname=libgotplt.so 347 348 Module module; 349 IRBuilder builder(module, config); 350 351 Path gotplt_o(TOPDIR); 352 gotplt_o.append("test/PLT/gotplt.o"); 353 Input* input = builder.CreateInput("gotplt.o", gotplt_o, Input::Object); 354 355 /// Sections 356 /// [ 0] NULL 00000000 000000 000000 00 0 0 0 357 builder.CreateELFHeader(*input, 358 "", 359 LDFileFormat::Null, 360 llvm::ELF::SHT_NULL, 361 0x0); 362 363 /// [ 1] .text PROGBITS 00000000 000034 000010 00 AX 0 0 4 364 LDSection* text = builder.CreateELFHeader(*input, 365 ".text", 366 llvm::ELF::SHT_PROGBITS, 367 llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR, 368 4); 369 370 SectionData* text_data = builder.CreateSectionData(*text); 371 static uint8_t text_content[] = { 0x00, 0x48, 0x2d, 0xe9, 372 0xfe, 0xff, 0xff, 0xeb, 373 0x00, 0x48, 0xbd, 0xe8, 374 0x0e, 0xf0, 0xa0, 0xe1 }; 375 Fragment* text_frag = builder.CreateRegion(text_content, 0x10); 376 builder.AppendFragment(*text_frag, *text_data); 377 378 /// [ 2] .rel.text REL 00000000 0002ac 000008 08 7 1 4 379 LDSection* rel_text = builder.CreateELFHeader(*input, 380 ".rel.text", 381 llvm::ELF::SHT_REL, 382 0x0, 4); 383 rel_text->setLink(text); 384 builder.CreateRelocData(*rel_text); 385 386 /// [ 3] .data PROGBITS 00000000 000044 000000 00 WA 0 0 4 387 LDSection* data = builder.CreateELFHeader(*input, 388 ".data", 389 llvm::ELF::SHT_PROGBITS, 390 llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE, 391 4); 392 393 /// [ 4] .bss NOBITS 00000000 000044 000000 00 WA 0 0 4 394 LDSection* bss = builder.CreateELFHeader(*input, 395 ".bss", 396 llvm::ELF::SHT_NOBITS, 397 llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE, 398 4); 399 builder.CreateBSS(*bss); 400 401 /// [ 5] .ARM.attributes ARM_ATTRIBUTES 00000000 000044 000020 00 0 0 1 402 LDSection* attr = builder.CreateELFHeader(*input, 403 ".ARM.attributes", 404 llvm::ELF::SHT_ARM_ATTRIBUTES, 405 0x0, 406 1); 407 408 SectionData* attr_data = builder.CreateSectionData(*attr); 409 static uint8_t attr_content[] = { 410 0x41, 0x1f, 0x00, 0x00, 411 0x00, 0x61, 0x65, 0x61, 412 0x62, 0x69, 0x00, 0x01, 413 0x15, 0x00, 0x00, 0x00, 414 0x06, 0x02, 0x08, 0x01, 415 0x09, 0x01, 0x14, 0x01, 416 0x15, 0x01, 0x17, 0x03, 417 0x18, 0x01, 0x19, 0x01 }; 418 Fragment* attr_frag = builder.CreateRegion(attr_content, 0x20); 419 builder.AppendFragment(*attr_frag, *attr_data); 420 421 /// Symbols 422 /// 1: 00000000 0 FILE LOCAL DEFAULT ABS Output/gotplt.bc 423 builder.AddSymbol(*input, 424 "Output/gotplt.bc", ResolveInfo::File, 425 ResolveInfo::Define, ResolveInfo::Local, 0); 426 /// 2: 00000000 0 SECTION LOCAL DEFAULT 1 427 builder.AddSymbol(*input, 428 ".text", ResolveInfo::Section, 429 ResolveInfo::Define, ResolveInfo::Local, 0, 0x0, text); 430 /// 3: 00000000 0 SECTION LOCAL DEFAULT 3 431 builder.AddSymbol(*input, 432 ".data", ResolveInfo::Section, 433 ResolveInfo::Define, ResolveInfo::Local, 0, 0x0, data); 434 /// 4: 00000000 0 SECTION LOCAL DEFAULT 4 435 builder.AddSymbol(*input, 436 ".bss", ResolveInfo::Section, 437 ResolveInfo::Define, ResolveInfo::Local, 0, 0x0, bss); 438 /// 5: 00000000 0 SECTION LOCAL DEFAULT 5 439 builder.AddSymbol(*input, 440 ".ARM.attributes", ResolveInfo::Section, 441 ResolveInfo::Define, ResolveInfo::Local, 0, 0x0, attr); 442 /// 6: 00000000 16 FUNC GLOBAL DEFAULT 1 _Z1fv 443 builder.AddSymbol(*input, 444 "_Z1fv", ResolveInfo::Function, 445 ResolveInfo::Define, ResolveInfo::Global, 446 16, 447 0x0, 448 text); 449 450 /// 7: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Z1gv 451 LDSymbol* z1gv = builder.AddSymbol(*input, 452 "_Z1gv", 453 ResolveInfo::NoType, 454 ResolveInfo::Undefined, 455 ResolveInfo::Global, 456 0); 457 458 /// Relocations 459 /// Offset Info Type Sym.Value Sym. Name 460 /// 00000004 0000071b R_ARM_PLT32 00000000 _Z1gv 461 builder.AddRelocation(*rel_text, llvm::ELF::R_ARM_PLT32, *z1gv, 0x4); 462 463 if (linker.link(module, builder)) { 464 linker.emit("libgotplt.so"); ///< -o libgotplt.so 465 } 466 467 Finalize(); 468 } 469