LinkerTest.cpp revision 22add6ff3426df1a85089fe6a6e1597ee3b6f300
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 22using namespace mcld; 23using namespace mcld::test; 24using namespace mcld::sys::fs; 25 26 27// Constructor can do set-up work for all test here. 28LinkerTest::LinkerTest() 29{ 30} 31 32// Destructor can do clean-up work that doesn't throw exceptions here. 33LinkerTest::~LinkerTest() 34{ 35} 36 37// SetUp() will be called immediately before each test. 38void LinkerTest::SetUp() 39{ 40} 41 42// TearDown() will be called immediately after each test. 43void LinkerTest::TearDown() 44{ 45} 46 47//===----------------------------------------------------------------------===// 48// Testcases 49//===----------------------------------------------------------------------===// 50TEST_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 79TEST_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 /// To configure linker before setting options. Linker::config sets up 88 /// default target-dependent configuration to LinkerConfig. 89 linker.config(config); 90 91 config.setCodeGenType(LinkerConfig::DynObj); ///< --shared 92 config.options().setSOName("libplasma.so"); ///< --soname=libplasma.so 93 config.options().setBsymbolic(); ///< -Bsymbolic 94 95 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 96 Path search_dir(TOPDIR); 97 search_dir.append("test/libs/ARM/Android/android-14"); 98 config.options().directories().insert(search_dir); 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. 136TEST_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 /// To configure linker before setting options. Linker::config sets up 145 /// default target-dependent configuration to LinkerConfig. 146 linker.config(config1); 147 148 config1.setCodeGenType(LinkerConfig::DynObj); ///< --shared 149 config1.options().setSOName("libplasma.once.so"); ///< --soname=libplasma.twice.so 150 config1.options().setBsymbolic(false); ///< -Bsymbolic 151 152 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 153 Path search_dir(TOPDIR); 154 search_dir.append("test/libs/ARM/Android/android-14"); 155 config1.options().directories().insert(search_dir); 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 /// To configure linker before setting options. Linker::config sets up 195 /// default target-dependent configuration to LinkerConfig. 196 linker.config(config2); 197 198 config2.setCodeGenType(LinkerConfig::DynObj); ///< --shared 199 config2.options().setSOName("libplasma.twice.so"); ///< --soname=libplasma.twice.exe 200 config2.options().setBsymbolic(); ///< -Bsymbolic 201 202 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 203 config2.options().directories().insert(search_dir); 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 231TEST_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 /// To configure linker before setting options. Linker::config sets up 240 /// default target-dependent configuration to LinkerConfig. 241 linker.config(config1); 242 243 config1.setCodeGenType(LinkerConfig::DynObj); ///< --shared 244 config1.options().setSOName("libplasma.once.so"); ///< --soname=libplasma.twice.so 245 config1.options().setBsymbolic(false); ///< -Bsymbolic 246 247 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 248 Path search_dir(TOPDIR); 249 search_dir.append("test/libs/ARM/Android/android-14"); 250 config1.options().directories().insert(search_dir); 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 /// To configure linker before setting options. Linker::config sets up 295 /// default target-dependent configuration to LinkerConfig. 296 linker.config(config2); 297 298 config2.setCodeGenType(LinkerConfig::DynObj); ///< --shared 299 config2.options().setSOName("libplasma.twice.so"); ///< --soname=libplasma.twice.exe 300 config2.options().setBsymbolic(); ///< -Bsymbolic 301 302 /// -L=${TOPDIR}/test/libs/ARM/Android/android-14 303 config2.options().directories().insert(search_dir); 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 333TEST_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 /// [ 0] NULL 00000000 000000 000000 00 0 0 0 356 builder.CreateELFHeader(*input, 357 "", 358 LDFileFormat::Null, 359 llvm::ELF::SHT_NULL, 360 0x0); 361 362 /// [ 1] .text PROGBITS 00000000 000034 000010 00 AX 0 0 4 363 LDSection* text = builder.CreateELFHeader(*input, 364 ".text", 365 llvm::ELF::SHT_PROGBITS, 366 llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR, 367 4); 368 369 SectionData* text_data = builder.CreateSectionData(*text); 370 static uint8_t text_content[] = { 0x00, 0x48, 0x2d, 0xe9, 371 0xfe, 0xff, 0xff, 0xeb, 372 0x00, 0x48, 0xbd, 0xe8, 373 0x0e, 0xf0, 0xa0, 0xe1 }; 374 Fragment* text_frag = builder.CreateRegion(text_content, 0x10); 375 builder.AppendFragment(*text_frag, *text_data); 376 377 // [ 3] .data PROGBITS 00000000 000044 000000 00 WA 0 0 4 378 builder.CreateELFHeader(*input, 379 ".data", 380 llvm::ELF::SHT_PROGBITS, 381 llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE, 382 4); 383 384 // [ 4] .bss NOBITS 00000000 000044 000000 00 WA 0 0 4 385 builder.CreateELFHeader(*input, 386 ".bss", 387 llvm::ELF::SHT_PROGBITS, 388 llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE, 389 4); 390 // [ 5] .ARM.attributes ARM_ATTRIBUTES 00000000 000044 000020 00 0 0 1 391 LDSection* attr = builder.CreateELFHeader(*input, 392 ".ARM.attributes", 393 llvm::ELF::SHT_ARM_ATTRIBUTES, 394 0x0, 395 4); 396 397 SectionData* attr_data = builder.CreateSectionData(*attr); 398 static uint8_t attr_content[] = { 399 0x41, 0x1f, 0x00, 0x00, 400 0x00, 0x61, 0x65, 0x61, 401 0x62, 0x69, 0x00, 0x01, 402 0x15, 0x00, 0x00, 0x00, 403 0x06, 0x02, 0x08, 0x01, 404 0x09, 0x01, 0x14, 0x01, 405 0x15, 0x01, 0x17, 0x03, 406 0x18, 0x01, 0x19, 0x01 }; 407 Fragment* attr_frag = builder.CreateRegion(attr_content, 0x20); 408 builder.AppendFragment(*attr_frag, *attr_data); 409 410 if (linker.link(module, builder)) { 411 linker.emit("libgotplt.so"); ///< -o libgotplt.so 412 } 413 414 Finalize(); 415} 416