1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (C) ?-1998 by Symantec 6 * Copyright (C) 2000-2021 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/elfobj.d, backend/elfobj.d) 10 */ 11 12 module dmd.backend.elfobj; 13 14 /**** 15 * Output to ELF object files 16 * http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html 17 */ 18 19 version (SCPP) 20 version = COMPILE; 21 version (MARS) 22 version = COMPILE; 23 24 version (COMPILE) 25 { 26 27 import core.stdc.stdio; 28 import core.stdc.stdlib; 29 import core.stdc.string; 30 31 import dmd.backend.barray; 32 import dmd.backend.cc; 33 import dmd.backend.cdef; 34 import dmd.backend.code; 35 import dmd.backend.code_x86; 36 import dmd.backend.mem; 37 import dmd.backend.aarray; 38 import dmd.backend.dlist; 39 import dmd.backend.el; 40 import dmd.backend.global; 41 import dmd.backend.obj; 42 import dmd.backend.oper; 43 import dmd.backend.outbuf; 44 import dmd.backend.symtab; 45 import dmd.backend.ty; 46 import dmd.backend.type; 47 48 extern (C++): 49 50 nothrow: 51 52 static if (1) 53 { 54 55 import dmd.backend.dwarf; 56 import dmd.backend.melf; 57 58 extern bool symbol_iscomdat2(Symbol* s) @system; 59 60 //#define DEBSYM 0x7E 61 62 private __gshared Outbuffer *fobjbuf; 63 64 enum MATCH_SECTION = 1; 65 66 enum DEST_LEN = (IDMAX + IDOHD + 1); 67 68 version (MARS) 69 { 70 // C++ name mangling is handled by front end 71 const(char)* cpp_mangle2(Symbol* s) { return &s.Sident[0]; } 72 } 73 else 74 const(char)* cpp_mangle2(Symbol* s) { return cpp_mangle(s); } 75 76 void addSegmentToComdat(segidx_t seg, segidx_t comdatseg); 77 78 /** 79 * If set the compiler requires full druntime support of the new 80 * section registration. 81 */ 82 //version (DMDV2) 83 static if (1) 84 enum DMDV2 = true; 85 else 86 enum DMDV2 = false; 87 enum REQUIRE_DSO_REGISTRY = (DMDV2 && (TARGET_LINUX || TARGET_FREEBSD || TARGET_DRAGONFLYBSD)); 88 89 /** 90 * If set, produce .init_array/.fini_array instead of legacy .ctors/.dtors . 91 * OpenBSD added the support in Aug 2016. Other supported platforms has 92 * supported .init_array for years. 93 */ 94 enum USE_INIT_ARRAY = !TARGET_OPENBSD; 95 96 /****** 97 * FreeBSD uses ELF, but the linker crashes with Elf comdats with the following message: 98 * /usr/bin/ld: BFD 2.15 [FreeBSD] 2004-05-23 internal error, aborting at 99 * /usr/src/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/elfcode.h 100 * line 213 in bfd_elf32_swap_symbol_out 101 * For the time being, just stick with Linux. 102 */ 103 104 enum ELF_COMDAT = TARGET_LINUX; 105 106 /*************************************************** 107 * Correspondence of relocation types 108 * 386 32 bit in 64 64 in 64 109 * R_386_32 R_X86_64_32 R_X86_64_64 110 * R_386_GOTOFF R_X86_64_PC32 R_X86_64_ 111 * R_386_GOTPC R_X86_64_ R_X86_64_ 112 * R_386_GOT32 R_X86_64_ R_X86_64_ 113 * R_386_TLS_GD R_X86_64_TLSGD R_X86_64_ 114 * R_386_TLS_IE R_X86_64_GOTTPOFF R_X86_64_ 115 * R_386_TLS_LE R_X86_64_TPOFF32 R_X86_64_ 116 * R_386_PLT32 R_X86_64_PLT32 R_X86_64_ 117 * R_386_PC32 R_X86_64_PC32 R_X86_64_ 118 */ 119 120 alias reltype_t = uint; 121 122 /****************************************** 123 */ 124 125 private __gshared Symbol *GOTsym; // global offset table reference 126 127 private Symbol *ElfObj_getGOTsym() 128 { 129 if (!GOTsym) 130 { 131 GOTsym = symbol_name("_GLOBAL_OFFSET_TABLE_",SCglobal,tspvoid); 132 } 133 return GOTsym; 134 } 135 136 void ElfObj_refGOTsym() 137 { 138 if (!GOTsym) 139 { 140 Symbol *s = ElfObj_getGOTsym(); 141 ElfObj_external(s); 142 } 143 } 144 145 //private void objfile_write(FILE *fd, void *buffer, uint len); 146 147 // The object file is built is several separate pieces 148 149 // Non-repeatable section types have single output buffers 150 // Pre-allocated buffers are defined for: 151 // Section Names string table 152 // Section Headers table 153 // Symbol table 154 // String table 155 // Notes section 156 // Comment data 157 158 // Section Names - String table for section names only 159 private __gshared Outbuffer *section_names; 160 enum SEC_NAMES_INIT = 800; 161 enum SEC_NAMES_INC = 400; 162 163 // Hash table for section_names 164 __gshared AApair2 *section_names_hashtable; 165 166 __gshared int jmpseg; 167 168 /* ======================================================================== */ 169 170 // String Table - String table for all other names 171 private __gshared Outbuffer *symtab_strings; 172 173 174 // Section Headers 175 __gshared Barray!(Elf32_Shdr) SecHdrTab; // section header table 176 177 const(char)* GET_SECTION_NAME(int secidx) 178 { 179 return cast(const(char)*)section_names.buf + SecHdrTab[secidx].sh_name; 180 } 181 182 // The relocation for text and data seems to get lost. 183 // Try matching the order gcc output them 184 // This means defining the sections and then removing them if they are 185 // not used. 186 187 enum 188 { 189 SHN_TEXT = 1, 190 SHN_RELTEXT = 2, 191 SHN_DATA = 3, 192 SHN_RELDATA = 4, 193 SHN_BSS = 5, 194 SHN_RODAT = 6, 195 SHN_STRINGS = 7, 196 SHN_SYMTAB = 8, 197 SHN_SECNAMES = 9, 198 SHN_COM = 10, 199 SHN_NOTE = 11, 200 SHN_GNUSTACK = 12, 201 SHN_CDATAREL = 13, 202 } 203 204 __gshared IDXSYM *mapsec2sym; 205 enum S2S_INC = 20; 206 207 private __gshared int symbol_idx; // Number of symbols in symbol table 208 private __gshared int local_cnt; // Number of symbols with STB_LOCAL 209 210 enum 211 { 212 STI_FILE = 1, // Where file symbol table entry is 213 STI_TEXT = 2, 214 STI_DATA = 3, 215 STI_BSS = 4, 216 STI_GCC = 5, // Where "gcc2_compiled" symbol is */ 217 STI_RODAT = 6, // Symbol for readonly data 218 STI_NOTE = 7, // Where note symbol table entry is 219 STI_COM = 8, 220 STI_CDATAREL = 9, // Symbol for readonly data with relocations 221 } 222 223 // NOTE: There seems to be a requirement that the read-only data have the 224 // same symbol table index and section index. Use section NOTE as a place 225 // holder. When a read-only string section is required, swap to NOTE. 226 227 __gshared 228 { 229 230 struct ElfObj 231 { 232 // Symbol Table 233 Barray!Elf32_Sym SymbolTable; 234 Barray!Elf64_Sym SymbolTable64; 235 236 Barray!(Symbol*) resetSyms; // Keep pointers to reset symbols 237 } 238 239 private ElfObj elfobj; 240 241 242 // Extended section header indices 243 private Outbuffer *shndx_data; 244 private const IDXSEC secidx_shndx = SHN_HIRESERVE + 1; 245 246 // Notes data (note currently used) 247 private Outbuffer *note_data; 248 private IDXSEC secidx_note; // Final table index for note data 249 250 // Comment data for compiler version 251 private Outbuffer *comment_data; 252 253 // Each compiler segment is an elf section 254 // Predefined compiler segments CODE,DATA,CDATA,UDATA map to indexes 255 // into SegData[] 256 // An additionl index is reserved for comment data 257 // New compiler segments are added to end. 258 // 259 // There doesn't seem to be any way to get reserved data space in the 260 // same section as initialized data or code, so section offsets should 261 // be continuous when adding data. Fix-ups anywhere withing existing data. 262 263 enum COMD = CDATAREL+1; 264 265 enum 266 { 267 OB_SEG_SIZ = 10, // initial number of segments supported 268 OB_SEG_INC = 10, // increment for additional segments 269 270 OB_CODE_STR = 100_000, // initial size for code 271 OB_CODE_INC = 100_000, // increment for additional code 272 OB_DATA_STR = 100_000, // initial size for data 273 OB_DATA_INC = 100_000, // increment for additional data 274 OB_CDATA_STR = 1024, // initial size for data 275 OB_CDATA_INC = 1024, // increment for additional data 276 OB_COMD_STR = 256, // initial size for comments 277 // increment as needed 278 OB_XTRA_STR = 250, // initial size for extra segments 279 OB_XTRA_INC = 10_000, // increment size 280 } 281 282 IDXSEC MAP_SEG2SECIDX(int seg) { return SegData[seg].SDshtidx; } 283 extern (D) 284 IDXSYM MAP_SEG2SYMIDX(int seg) { return SegData[seg].SDsymidx; } 285 Elf32_Shdr* MAP_SEG2SEC(int seg) { return &SecHdrTab[MAP_SEG2SECIDX(seg)]; } 286 int MAP_SEG2TYP(int seg) { return MAP_SEG2SEC(seg).sh_flags & SHF_EXECINSTR ? CODE : DATA; } 287 288 extern Rarray!(seg_data*) SegData; 289 290 int seg_tlsseg = UNKNOWN; 291 int seg_tlsseg_bss = UNKNOWN; 292 293 } 294 295 296 /******************************* 297 * Output a string into a string table 298 * Input: 299 * strtab = string table for entry 300 * str = string to add 301 * 302 * Returns index into the specified string table. 303 */ 304 305 IDXSTR ElfObj_addstr(Outbuffer *strtab, const(char)* str) 306 { 307 //dbg_printf("ElfObj_addstr(strtab = x%x str = '%s')\n",strtab,str); 308 IDXSTR idx = cast(IDXSTR)strtab.length(); // remember starting offset 309 strtab.writeString(str); 310 //dbg_printf("\tidx %d, new size %d\n",idx,strtab.length()); 311 return idx; 312 } 313 314 /******************************* 315 * Output a mangled string into the symbol string table 316 * Input: 317 * str = string to add 318 * 319 * Returns index into the table. 320 */ 321 322 private IDXSTR elf_addmangled(Symbol *s) 323 { 324 //printf("elf_addmangled(%s)\n", s.Sident.ptr); 325 char[DEST_LEN] dest = void; 326 327 IDXSTR namidx = cast(IDXSTR)symtab_strings.length(); 328 size_t len; 329 char *destr = obj_mangle2(s, dest.ptr, &len); 330 const(char)* name = destr; 331 if (CPP && name[0] == '_' && name[1] == '_') 332 { 333 if (strncmp(name,"__ct__",6) == 0) 334 { 335 name += 4; 336 len -= 4; 337 } 338 static if (0) 339 { 340 switch(name[2]) 341 { 342 case 'c': 343 if (strncmp(name,"__ct__",6) == 0) 344 name += 4; 345 break; 346 case 'd': 347 if (strcmp(name,"__dl__FvP") == 0) 348 name = "__builtin_delete"; 349 break; 350 case 'v': 351 //if (strcmp(name,"__vec_delete__FvPiUIPi") == 0) 352 //name = "__builtin_vec_del"; 353 //else 354 //if (strcmp(name,"__vn__FPUI") == 0) 355 //name = "__builtin_vec_new"; 356 break; 357 case 'n': 358 if (strcmp(name,"__nw__FPUI") == 0) 359 name = "__builtin_new"; 360 break; 361 362 default: 363 break; 364 } 365 } 366 } 367 else if (tyfunc(s.ty()) && s.Sfunc && s.Sfunc.Fredirect) 368 { 369 name = s.Sfunc.Fredirect; 370 len = strlen(name); 371 } 372 symtab_strings.write(name, len + 1); 373 if (destr != dest.ptr) // if we resized result 374 mem_free(destr); 375 //dbg_printf("\telf_addmagled symtab_strings %s namidx %d len %d size %d\n",name, namidx,len,symtab_strings.length()); 376 return namidx; 377 } 378 379 /******************************* 380 * Output a symbol into the symbol table 381 * Input: 382 * stridx = string table index for name 383 * val = value associated with symbol 384 * sz = symbol size 385 * typ = symbol type 386 * bind = symbol binding 387 * sec = index of section where symbol is defined 388 * visibility = visibility of symbol (STV_xxxx) 389 * 390 * Returns the symbol table index for the symbol 391 */ 392 393 private IDXSYM elf_addsym(IDXSTR nam, targ_size_t val, uint sz, 394 uint typ, uint bind, IDXSEC sec, 395 ubyte visibility = STV_DEFAULT) 396 { 397 //dbg_printf("elf_addsym(nam %d, val %d, sz %x, typ %x, bind %x, sec %d\n", 398 //nam,val,sz,typ,bind,sec); 399 400 /* We want globally defined data symbols to have a size because 401 * zero sized symbols break copy relocations for shared libraries. 402 */ 403 if(sz == 0 && (bind == STB_GLOBAL || bind == STB_WEAK) && 404 (typ == STT_OBJECT || typ == STT_TLS) && 405 sec != SHN_UNDEF) 406 sz = 1; // so fake it if it doesn't 407 408 if (sec > SHN_HIRESERVE) 409 { // If the section index is too big we need to store it as 410 // extended section header index. 411 if (!shndx_data) 412 { 413 shndx_data = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 414 assert(shndx_data); 415 shndx_data.reserve(50 * (Elf64_Word).sizeof); 416 } 417 // fill with zeros up to symbol_idx 418 const size_t shndx_idx = shndx_data.length() / Elf64_Word.sizeof; 419 shndx_data.writezeros(cast(uint)((symbol_idx - shndx_idx) * Elf64_Word.sizeof)); 420 421 shndx_data.write32(sec); 422 sec = SHN_XINDEX; 423 } 424 425 if (I64) 426 { 427 Elf64_Sym* sym = elfobj.SymbolTable64.push(); 428 sym.st_name = nam; 429 sym.st_value = val; 430 sym.st_size = sz; 431 sym.st_info = cast(ubyte)ELF64_ST_INFO(cast(ubyte)bind,cast(ubyte)typ); 432 sym.st_other = visibility; 433 sym.st_shndx = cast(ushort)sec; 434 } 435 else 436 { 437 Elf32_Sym* sym = elfobj.SymbolTable.push(); 438 sym.st_name = nam; 439 sym.st_value = cast(uint)val; 440 sym.st_size = sz; 441 sym.st_info = ELF32_ST_INFO(cast(ubyte)bind,cast(ubyte)typ); 442 sym.st_other = visibility; 443 sym.st_shndx = cast(ushort)sec; 444 } 445 446 if (bind == STB_LOCAL) 447 local_cnt++; 448 //dbg_printf("\treturning symbol table index %d\n",symbol_idx); 449 return symbol_idx++; 450 } 451 452 /******************************* 453 * Create a new section header table entry. 454 * 455 * Input: 456 * name = section name 457 * suffix = suffix for name or null 458 * type = type of data in section sh_type 459 * flags = attribute flags sh_flags 460 * Output: 461 * assigned number for this section 462 * Note: Sections will be reordered on output 463 */ 464 465 private IDXSEC elf_newsection2( 466 Elf32_Word name, 467 Elf32_Word type, 468 Elf32_Word flags, 469 Elf32_Addr addr, 470 Elf32_Off offset, 471 Elf32_Word size, 472 Elf32_Word link, 473 Elf32_Word info, 474 Elf32_Word addralign, 475 Elf32_Word entsize) 476 { 477 Elf32_Shdr sec; 478 479 sec.sh_name = name; 480 sec.sh_type = type; 481 sec.sh_flags = flags; 482 sec.sh_addr = addr; 483 sec.sh_offset = offset; 484 sec.sh_size = size; 485 sec.sh_link = link; 486 sec.sh_info = info; 487 sec.sh_addralign = addralign; 488 sec.sh_entsize = entsize; 489 490 if (SecHdrTab.length == SHN_LORESERVE) 491 { // insert dummy null sections to skip reserved section indices 492 foreach (i; SHN_LORESERVE .. SHN_HIRESERVE + 1) 493 SecHdrTab.push(); 494 // shndx itself becomes the first section with an extended index 495 IDXSTR namidx = ElfObj_addstr(section_names, ".symtab_shndx"); 496 elf_newsection2(namidx,SHT_SYMTAB_SHNDX,0,0,0,0,SHN_SYMTAB,0,4,4); 497 } 498 const si = SecHdrTab.length; 499 *SecHdrTab.push() = sec; 500 return cast(IDXSEC)si; 501 } 502 503 /** 504 Add a new section name or get the string table index of an existing entry. 505 506 Params: 507 name = name of section 508 suffix = append to name 509 padded = set to true when entry was newly added 510 Returns: 511 pointer to Pair, where the first field is the string index of the new or existing section name, 512 and the second field is its segment index 513 */ 514 private Pair* elf_addsectionname(const(char)* name, const(char)* suffix = null, bool *padded = null) 515 { 516 IDXSTR namidx = cast(IDXSTR)section_names.length(); 517 section_names.writeString(name); 518 if (suffix) 519 { // Append suffix string 520 section_names.setsize(cast(uint)section_names.length() - 1); // back up over terminating 0 521 section_names.writeString(suffix); 522 } 523 Pair* pidx = section_names_hashtable.get(namidx, cast(uint)section_names.length() - 1); 524 if (pidx.start) 525 { 526 // this section name already exists, remove addition 527 section_names.setsize(namidx); 528 return pidx; 529 } 530 if (padded) 531 *padded = true; 532 pidx.start = namidx; 533 return pidx; 534 } 535 536 private IDXSEC elf_newsection(const(char)* name, const(char)* suffix, 537 Elf32_Word type, Elf32_Word flags) 538 { 539 // dbg_printf("elf_newsection(%s,%s,type %d, flags x%x)\n", 540 // name?name:"",suffix?suffix:"",type,flags); 541 bool added = false; 542 Pair* pidx = elf_addsectionname(name, suffix, &added); 543 assert(added); 544 545 return elf_newsection2(pidx.start,type,flags,0,0,0,0,0,0,0); 546 } 547 548 /************************** 549 * Ouput read only data and generate a symbol for it. 550 * 551 */ 552 553 Symbol *ElfObj_sym_cdata(tym_t ty,char *p,int len) 554 { 555 Symbol *s; 556 557 static if (0) 558 { 559 if (OPT_IS_SET(OPTfwritable_strings)) 560 { 561 alignOffset(DATA, tysize(ty)); 562 s = symboldata(Offset(DATA), ty); 563 SegData[DATA].SDbuf.write(p,len); 564 s.Sseg = DATA; 565 s.Soffset = Offset(DATA); // Remember its offset into DATA section 566 Offset(DATA) += len; 567 s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern; 568 return s; 569 } 570 } 571 572 //printf("ElfObj_sym_cdata(ty = %x, p = %x, len = %d, Offset(CDATA) = %x)\n", ty, p, len, Offset(CDATA)); 573 alignOffset(CDATA, tysize(ty)); 574 s = symboldata(Offset(CDATA), ty); 575 ElfObj_bytes(CDATA, Offset(CDATA), len, p); 576 s.Sseg = CDATA; 577 578 s.Sfl = /*(config.flags3 & CFG3pic) ? FLgotoff :*/ FLextern; 579 return s; 580 } 581 582 /************************** 583 * Ouput read only data for data. 584 * Output: 585 * *pseg segment of that data 586 * Returns: 587 * offset of that data 588 */ 589 590 int ElfObj_data_readonly(char *p, int len, int *pseg) 591 { 592 int oldoff = cast(int)Offset(CDATA); 593 SegData[CDATA].SDbuf.reserve(len); 594 SegData[CDATA].SDbuf.writen(p,len); 595 Offset(CDATA) += len; 596 *pseg = CDATA; 597 return oldoff; 598 } 599 600 int ElfObj_data_readonly(char *p, int len) 601 { 602 int pseg; 603 604 return ElfObj_data_readonly(p, len, &pseg); 605 } 606 607 /****************************** 608 * Get segment for readonly string literals. 609 * The linker will pool strings in this section. 610 * Params: 611 * sz = number of bytes per character (1, 2, or 4) 612 * Returns: 613 * segment index 614 */ 615 int ElfObj_string_literal_segment(uint sz) 616 { 617 /* Elf special sections: 618 * .rodata.strM.N - M is size of character 619 * N is alignment 620 * .rodata.cstN - N fixed size readonly constants N bytes in size, 621 * aligned to the same size 622 */ 623 static immutable char[4][3] name = [ "1.1", "2.2", "4.4" ]; 624 const int i = (sz == 4) ? 2 : sz - 1; 625 const IDXSEC seg = 626 ElfObj_getsegment(".rodata.str".ptr, name[i].ptr, SHT_PROGBITS, SHF_ALLOC | SHF_MERGE | SHF_STRINGS, sz); 627 return seg; 628 } 629 630 /****************************** 631 * Perform initialization that applies to all .o output files. 632 * Called before any other obj_xxx routines 633 */ 634 635 Obj ElfObj_init(Outbuffer *objbuf, const(char)* filename, const(char)* csegname) 636 { 637 //printf("ElfObj_init()\n"); 638 Obj obj = cast(Obj)mem_calloc(__traits(classInstanceSize, Obj)); 639 640 cseg = CODE; 641 fobjbuf = objbuf; 642 643 mapsec2sym = null; 644 note_data = null; 645 secidx_note = 0; 646 comment_data = null; 647 seg_tlsseg = UNKNOWN; 648 seg_tlsseg_bss = UNKNOWN; 649 GOTsym = null; 650 651 // Initialize buffers 652 653 if (symtab_strings) 654 symtab_strings.setsize(1); 655 else 656 { 657 symtab_strings = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 658 assert(symtab_strings); 659 symtab_strings.reserve(2048); 660 symtab_strings.writeByte(0); 661 } 662 663 SecHdrTab.reset(); 664 665 enum NAMIDX : IDXSTR 666 { 667 NONE = 0, 668 SYMTAB = 1, // .symtab 669 STRTAB = 9, // .strtab 670 SHSTRTAB = 17, // .shstrtab 671 TEXT = 27, // .text 672 DATA = 33, // .data 673 BSS = 39, // .bss 674 NOTE = 44, // .note 675 COMMENT = 50, // .comment 676 RODATA = 59, // .rodata 677 GNUSTACK = 67, // .note.GNU-stack 678 CDATAREL = 83, // .data.rel.ro 679 RELTEXT = 96, // .rel.text and .rela.text 680 RELDATA = 106, // .rel.data 681 RELDATA64 = 107, // .rela.data 682 } 683 684 if (I64) 685 { 686 static immutable char[107 + 12] section_names_init64 = 687 "\0.symtab\0.strtab\0.shstrtab\0.text\0.data\0.bss\0.note" ~ 688 "\0.comment\0.rodata\0.note.GNU-stack\0.data.rel.ro\0.rela.text\0.rela.data"; 689 690 if (section_names) 691 section_names.setsize(section_names_init64.sizeof); 692 else 693 { 694 section_names = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 695 assert(section_names); 696 section_names.reserve(1024); 697 section_names.writen(section_names_init64.ptr, section_names_init64.sizeof); 698 } 699 700 if (section_names_hashtable) 701 AApair2.destroy(section_names_hashtable); 702 section_names_hashtable = AApair2.create(§ion_names.buf); 703 704 // name,type,flags,addr,offset,size,link,info,addralign,entsize 705 elf_newsection2(0, SHT_NULL, 0, 0,0,0,0,0, 0,0); 706 elf_newsection2(NAMIDX.TEXT,SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR,0,0,0,0,0, 4,0); 707 elf_newsection2(NAMIDX.RELTEXT,SHT_RELA, 0,0,0,0,SHN_SYMTAB, SHN_TEXT, 8,0x18); 708 elf_newsection2(NAMIDX.DATA,SHT_PROGBITS,SHF_ALLOC|SHF_WRITE, 0,0,0,0,0, 8,0); 709 elf_newsection2(NAMIDX.RELDATA64,SHT_RELA, 0,0,0,0,SHN_SYMTAB, SHN_DATA, 8,0x18); 710 elf_newsection2(NAMIDX.BSS, SHT_NOBITS,SHF_ALLOC|SHF_WRITE, 0,0,0,0,0, 16,0); 711 elf_newsection2(NAMIDX.RODATA,SHT_PROGBITS,SHF_ALLOC, 0,0,0,0,0, 16,0); 712 elf_newsection2(NAMIDX.STRTAB,SHT_STRTAB, 0, 0,0,0,0,0, 1,0); 713 elf_newsection2(NAMIDX.SYMTAB,SHT_SYMTAB, 0, 0,0,0,0,0, 8,0); 714 elf_newsection2(NAMIDX.SHSTRTAB,SHT_STRTAB, 0, 0,0,0,0,0, 1,0); 715 elf_newsection2(NAMIDX.COMMENT, SHT_PROGBITS,0, 0,0,0,0,0, 1,0); 716 elf_newsection2(NAMIDX.NOTE,SHT_NOTE, 0, 0,0,0,0,0, 1,0); 717 elf_newsection2(NAMIDX.GNUSTACK,SHT_PROGBITS,0, 0,0,0,0,0, 1,0); 718 elf_newsection2(NAMIDX.CDATAREL,SHT_PROGBITS,SHF_ALLOC|SHF_WRITE,0,0,0,0,0, 16,0); 719 720 foreach (idxname; __traits(allMembers, NAMIDX)[1 .. $]) 721 { 722 NAMIDX idx = mixin("NAMIDX." ~ idxname); 723 section_names_hashtable.get(idx, cast(uint)section_names_init64.sizeof).start = idx; 724 } 725 } 726 else 727 { 728 static immutable char[106 + 12] section_names_init = 729 "\0.symtab\0.strtab\0.shstrtab\0.text\0.data\0.bss\0.note" ~ 730 "\0.comment\0.rodata\0.note.GNU-stack\0.data.rel.ro\0.rel.text\0.rel.data"; 731 732 if (section_names) 733 section_names.setsize(section_names_init.sizeof); 734 else 735 { 736 section_names = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 737 assert(section_names); 738 section_names.reserve(100*1024); 739 section_names.writen(section_names_init.ptr, section_names_init.sizeof); 740 } 741 742 if (section_names_hashtable) 743 AApair2.destroy(section_names_hashtable); 744 section_names_hashtable = AApair2.create(§ion_names.buf); 745 746 // name,type,flags,addr,offset,size,link,info,addralign,entsize 747 elf_newsection2(0, SHT_NULL, 0, 0,0,0,0,0, 0,0); 748 elf_newsection2(NAMIDX.TEXT,SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR,0,0,0,0,0, 16,0); 749 elf_newsection2(NAMIDX.RELTEXT,SHT_REL, 0,0,0,0,SHN_SYMTAB, SHN_TEXT, 4,8); 750 elf_newsection2(NAMIDX.DATA,SHT_PROGBITS,SHF_ALLOC|SHF_WRITE, 0,0,0,0,0, 4,0); 751 elf_newsection2(NAMIDX.RELDATA,SHT_REL, 0,0,0,0,SHN_SYMTAB, SHN_DATA, 4,8); 752 elf_newsection2(NAMIDX.BSS, SHT_NOBITS,SHF_ALLOC|SHF_WRITE, 0,0,0,0,0, 32,0); 753 elf_newsection2(NAMIDX.RODATA,SHT_PROGBITS,SHF_ALLOC, 0,0,0,0,0, 4,0); 754 elf_newsection2(NAMIDX.STRTAB,SHT_STRTAB, 0, 0,0,0,0,0, 1,0); 755 elf_newsection2(NAMIDX.SYMTAB,SHT_SYMTAB, 0, 0,0,0,0,0, 4,0); 756 elf_newsection2(NAMIDX.SHSTRTAB,SHT_STRTAB, 0, 0,0,0,0,0, 1,0); 757 elf_newsection2(NAMIDX.COMMENT, SHT_PROGBITS,0, 0,0,0,0,0, 1,0); 758 elf_newsection2(NAMIDX.NOTE,SHT_NOTE, 0, 0,0,0,0,0, 1,0); 759 elf_newsection2(NAMIDX.GNUSTACK,SHT_PROGBITS,0, 0,0,0,0,0, 1,0); 760 elf_newsection2(NAMIDX.CDATAREL,SHT_PROGBITS,SHF_ALLOC|SHF_WRITE,0,0,0,0,0, 1,0); 761 762 foreach (idxname; __traits(allMembers, NAMIDX)[1 .. $]) 763 { 764 NAMIDX idx = mixin("NAMIDX." ~ idxname); 765 section_names_hashtable.get(idx, cast(uint)section_names_init.sizeof).start = idx; 766 } 767 } 768 769 elfobj.SymbolTable.reset(); 770 elfobj.SymbolTable64.reset(); 771 772 foreach (s; elfobj.resetSyms) 773 symbol_reset(s); 774 elfobj.resetSyms.reset(); 775 776 if (shndx_data) 777 shndx_data.reset(); 778 symbol_idx = 0; 779 local_cnt = 0; 780 // The symbols that every object file has 781 elf_addsym(0, 0, 0, STT_NOTYPE, STB_LOCAL, 0); 782 elf_addsym(0, 0, 0, STT_FILE, STB_LOCAL, SHN_ABS); // STI_FILE 783 elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_TEXT); // STI_TEXT 784 elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_DATA); // STI_DATA 785 elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_BSS); // STI_BSS 786 elf_addsym(0, 0, 0, STT_NOTYPE, STB_LOCAL, SHN_TEXT); // STI_GCC 787 elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_RODAT); // STI_RODAT 788 elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_NOTE); // STI_NOTE 789 elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_COM); // STI_COM 790 elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, SHN_CDATAREL); // STI_CDATAREL 791 792 // Initialize output buffers for CODE, DATA and COMMENTS 793 // (NOTE not supported, BSS not required) 794 795 SegData.reset(); // recycle memory 796 SegData.push(); // element 0 is reserved 797 798 elf_addsegment2(SHN_TEXT, STI_TEXT, SHN_RELTEXT); 799 assert(SegData[CODE].SDseg == CODE); 800 801 elf_addsegment2(SHN_DATA, STI_DATA, SHN_RELDATA); 802 assert(SegData[DATA].SDseg == DATA); 803 804 elf_addsegment2(SHN_RODAT, STI_RODAT, 0); 805 assert(SegData[CDATA].SDseg == CDATA); 806 807 elf_addsegment2(SHN_BSS, STI_BSS, 0); 808 assert(SegData[UDATA].SDseg == UDATA); 809 810 elf_addsegment2(SHN_CDATAREL, STI_CDATAREL, 0); 811 assert(SegData[CDATAREL].SDseg == CDATAREL); 812 813 elf_addsegment2(SHN_COM, STI_COM, 0); 814 assert(SegData[COMD].SDseg == COMD); 815 816 dwarf_initfile(filename); 817 return obj; 818 } 819 820 /************************** 821 * Initialize the start of object output for this particular .o file. 822 * 823 * Input: 824 * filename: Name of source file 825 * csegname: User specified default code segment name 826 */ 827 828 void ElfObj_initfile(const(char)* filename, const(char)* csegname, const(char)* modname) 829 { 830 //dbg_printf("ElfObj_initfile(filename = %s, modname = %s)\n",filename,modname); 831 832 IDXSTR name = ElfObj_addstr(symtab_strings, filename); 833 if (I64) 834 elfobj.SymbolTable64[STI_FILE].st_name = name; 835 else 836 elfobj.SymbolTable[STI_FILE].st_name = name; 837 838 static if (0) 839 { 840 // compiler flag for linker 841 if (I64) 842 elfobj.SymbolTable64[STI_GCC].st_name = ElfObj_addstr(symtab_strings,"gcc2_compiled."); 843 else 844 elfobj.SymbolTable[STI_GCC].st_name = ElfObj_addstr(symtab_strings,"gcc2_compiled."); 845 } 846 847 if (csegname && *csegname && strcmp(csegname,".text")) 848 { // Define new section and make it the default for cseg segment 849 // NOTE: cseg is initialized to CODE 850 const newsecidx = elf_newsection(csegname,null,SHT_PROGBITS,SHF_ALLOC|SHF_EXECINSTR); 851 SecHdrTab[newsecidx].sh_addralign = 4; 852 SegData[cseg].SDshtidx = newsecidx; 853 SegData[cseg].SDsymidx = elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, newsecidx); 854 } 855 if (config.fulltypes) 856 dwarf_initmodule(filename, modname); 857 } 858 859 /*************************** 860 * Renumber symbols so they are 861 * ordered as locals, weak and then global 862 * Returns: 863 * sorted symbol table, caller must free with util_free() 864 */ 865 866 void *elf_renumbersyms() 867 { void *symtab; 868 int nextlocal = 0; 869 int nextglobal = local_cnt; 870 871 SYMIDX *sym_map = cast(SYMIDX *)util_malloc(SYMIDX.sizeof,symbol_idx); 872 873 if (I64) 874 { 875 Elf64_Sym *oldsymtab = &elfobj.SymbolTable64[0]; 876 Elf64_Sym *symtabend = oldsymtab+symbol_idx; 877 878 symtab = util_malloc(Elf64_Sym.sizeof,symbol_idx); 879 880 Elf64_Sym *sl = cast(Elf64_Sym *)symtab; 881 Elf64_Sym *sg = sl + local_cnt; 882 883 int old_idx = 0; 884 for(Elf64_Sym *s = oldsymtab; s != symtabend; s++) 885 { // reorder symbol and map new #s to old 886 int bind = ELF64_ST_BIND(s.st_info); 887 if (bind == STB_LOCAL) 888 { 889 *sl++ = *s; 890 sym_map[old_idx] = nextlocal++; 891 } 892 else 893 { 894 *sg++ = *s; 895 sym_map[old_idx] = nextglobal++; 896 } 897 old_idx++; 898 } 899 } 900 else 901 { 902 Elf32_Sym *oldsymtab = &elfobj.SymbolTable[0]; 903 Elf32_Sym *symtabend = oldsymtab+symbol_idx; 904 905 symtab = util_malloc(Elf32_Sym.sizeof,symbol_idx); 906 907 Elf32_Sym *sl = cast(Elf32_Sym *)symtab; 908 Elf32_Sym *sg = sl + local_cnt; 909 910 int old_idx = 0; 911 for(Elf32_Sym *s = oldsymtab; s != symtabend; s++) 912 { // reorder symbol and map new #s to old 913 int bind = ELF32_ST_BIND(s.st_info); 914 if (bind == STB_LOCAL) 915 { 916 *sl++ = *s; 917 sym_map[old_idx] = nextlocal++; 918 } 919 else 920 { 921 *sg++ = *s; 922 sym_map[old_idx] = nextglobal++; 923 } 924 old_idx++; 925 } 926 } 927 928 // Reorder extended section header indices 929 if (shndx_data && shndx_data.length()) 930 { 931 // fill with zeros up to symbol_idx 932 const size_t shndx_idx = shndx_data.length() / Elf64_Word.sizeof; 933 shndx_data.writezeros(cast(uint)((symbol_idx - shndx_idx) * Elf64_Word.sizeof)); 934 935 Elf64_Word *old_buf = cast(Elf64_Word *)shndx_data.buf; 936 Elf64_Word *tmp_buf = cast(Elf64_Word *)util_malloc(Elf64_Word.sizeof, symbol_idx); 937 for (SYMIDX old_idx = 0; old_idx < symbol_idx; ++old_idx) 938 { 939 const SYMIDX new_idx = sym_map[old_idx]; 940 tmp_buf[new_idx] = old_buf[old_idx]; 941 } 942 memcpy(old_buf, tmp_buf, Elf64_Word.sizeof * symbol_idx); 943 util_free(tmp_buf); 944 } 945 946 // Renumber the relocations 947 for (int i = 1; i < SegData.length; i++) 948 { // Map indicies in the segment table 949 seg_data *pseg = SegData[i]; 950 pseg.SDsymidx = cast(uint) sym_map[pseg.SDsymidx]; 951 952 if (SecHdrTab[pseg.SDshtidx].sh_type == SHT_GROUP) 953 { // map symbol index of group section header 954 uint oidx = SecHdrTab[pseg.SDshtidx].sh_info; 955 assert(oidx < symbol_idx); 956 // we only have one symbol table 957 assert(SecHdrTab[pseg.SDshtidx].sh_link == SHN_SYMTAB); 958 SecHdrTab[pseg.SDshtidx].sh_info = cast(uint) sym_map[oidx]; 959 } 960 961 if (pseg.SDrel) 962 { 963 if (I64) 964 { 965 Elf64_Rela *rel = cast(Elf64_Rela *) pseg.SDrel.buf; 966 for (int r = 0; r < pseg.SDrelcnt; r++) 967 { 968 uint t = ELF64_R_TYPE(rel.r_info); 969 uint si = ELF64_R_SYM(rel.r_info); 970 assert(si < symbol_idx); 971 rel.r_info = ELF64_R_INFO(sym_map[si],t); 972 rel++; 973 } 974 } 975 else 976 { 977 Elf32_Rel *rel = cast(Elf32_Rel *) pseg.SDrel.buf; 978 assert(pseg.SDrelcnt == pseg.SDrel.length() / Elf32_Rel.sizeof); 979 for (int r = 0; r < pseg.SDrelcnt; r++) 980 { 981 uint t = ELF32_R_TYPE(rel.r_info); 982 uint si = ELF32_R_SYM(rel.r_info); 983 assert(si < symbol_idx); 984 rel.r_info = ELF32_R_INFO(cast(uint) sym_map[si],t); 985 rel++; 986 } 987 } 988 } 989 } 990 991 return symtab; 992 } 993 994 995 /*************************** 996 * Fixup and terminate object file. 997 */ 998 999 void ElfObj_termfile() 1000 { 1001 //dbg_printf("ElfObj_termfile\n"); 1002 if (configv.addlinenumbers) 1003 { 1004 dwarf_termmodule(); 1005 } 1006 } 1007 1008 /********************************* 1009 * Terminate package. 1010 */ 1011 1012 void ElfObj_term(const(char)* objfilename) 1013 { 1014 //printf("ElfObj_term()\n"); 1015 version (SCPP) 1016 { 1017 if (!errcnt) 1018 { 1019 outfixlist(); // backpatches 1020 } 1021 } 1022 else 1023 { 1024 outfixlist(); // backpatches 1025 } 1026 1027 if (configv.addlinenumbers) 1028 { 1029 dwarf_termfile(); 1030 } 1031 1032 version (MARS) 1033 { 1034 if (config.useModuleInfo) 1035 obj_rtinit(); 1036 } 1037 1038 version (SCPP) 1039 { 1040 if (errcnt) 1041 return; 1042 } 1043 1044 int foffset; 1045 Elf32_Shdr *sechdr; 1046 seg_data *seg; 1047 void *symtab = elf_renumbersyms(); 1048 FILE *fd = null; 1049 1050 int hdrsize = (I64 ? Elf64_Ehdr.sizeof : Elf32_Ehdr.sizeof); 1051 1052 ushort e_shnum; 1053 if (SecHdrTab.length < SHN_LORESERVE) 1054 e_shnum = cast(ushort)SecHdrTab.length; 1055 else 1056 { 1057 e_shnum = SHN_UNDEF; 1058 SecHdrTab[0].sh_size = cast(uint)SecHdrTab.length; 1059 } 1060 // uint16_t e_shstrndx = SHN_SECNAMES; 1061 fobjbuf.writezeros(hdrsize); 1062 1063 // Walk through sections determining size and file offsets 1064 // Sections will be output in the following order 1065 // Null segment 1066 // For each Code/Data Segment 1067 // code/data to load 1068 // relocations without addens 1069 // .bss 1070 // notes 1071 // comments 1072 // section names table 1073 // symbol table 1074 // strings table 1075 1076 foffset = hdrsize; // start after header 1077 // section header table at end 1078 1079 // 1080 // First output individual section data associate with program 1081 // code and data 1082 // 1083 //printf("Setup offsets and sizes foffset %d\n\tSecHdrTab.length %d, SegData.length %d\n",foffset,cast(int)SecHdrTab.length,SegData.length); 1084 foreach (int i; 1 .. cast(int)SegData.length) 1085 { 1086 seg_data *pseg = SegData[i]; 1087 Elf32_Shdr *sechdr2 = MAP_SEG2SEC(i); // corresponding section 1088 if (sechdr2.sh_addralign < pseg.SDalignment) 1089 sechdr2.sh_addralign = pseg.SDalignment; 1090 foffset = elf_align(sechdr2.sh_addralign,foffset); 1091 if (i == UDATA) // 0, BSS never allocated 1092 { // but foffset as if it has 1093 sechdr2.sh_offset = foffset; 1094 sechdr2.sh_size = cast(uint)pseg.SDoffset; 1095 // accumulated size 1096 continue; 1097 } 1098 else if (sechdr2.sh_type == SHT_NOBITS) // .tbss never allocated 1099 { 1100 sechdr2.sh_offset = foffset; 1101 sechdr2.sh_size = cast(uint)pseg.SDoffset; 1102 // accumulated size 1103 continue; 1104 } 1105 else if (!pseg.SDbuf) 1106 continue; // For others leave sh_offset as 0 1107 1108 sechdr2.sh_offset = foffset; 1109 //printf("\tsection name %d,",sechdr2.sh_name); 1110 if (pseg.SDbuf && pseg.SDbuf.length()) 1111 { 1112 //printf(" - size %d\n",pseg.SDbuf.length()); 1113 const size_t size = pseg.SDbuf.length(); 1114 fobjbuf.write(pseg.SDbuf.buf, cast(uint)size); 1115 const int nfoffset = elf_align(sechdr2.sh_addralign, cast(uint)(foffset + size)); 1116 sechdr2.sh_size = nfoffset - foffset; 1117 foffset = nfoffset; 1118 } 1119 //printf(" assigned offset %d, size %d\n",foffset,sechdr2.sh_size); 1120 } 1121 1122 // 1123 // Next output any notes or comments 1124 // 1125 if (note_data) 1126 { 1127 sechdr = &SecHdrTab[secidx_note]; // Notes 1128 sechdr.sh_size = cast(uint)note_data.length(); 1129 sechdr.sh_offset = foffset; 1130 fobjbuf.write(note_data.buf, sechdr.sh_size); 1131 foffset += sechdr.sh_size; 1132 } 1133 1134 if (comment_data) 1135 { 1136 sechdr = &SecHdrTab[SHN_COM]; // Comments 1137 sechdr.sh_size = cast(uint)comment_data.length(); 1138 sechdr.sh_offset = foffset; 1139 fobjbuf.write(comment_data.buf, sechdr.sh_size); 1140 foffset += sechdr.sh_size; 1141 } 1142 1143 // 1144 // Then output string table for section names 1145 // 1146 sechdr = &SecHdrTab[SHN_SECNAMES]; // Section Names 1147 sechdr.sh_size = cast(uint)section_names.length(); 1148 sechdr.sh_offset = foffset; 1149 //dbg_printf("section names offset %d\n",foffset); 1150 fobjbuf.write(section_names.buf, sechdr.sh_size); 1151 foffset += sechdr.sh_size; 1152 1153 // 1154 // Symbol table and string table for symbols next 1155 // 1156 //dbg_printf("output symbol table size %d\n",SYMbuf.length()); 1157 sechdr = &SecHdrTab[SHN_SYMTAB]; // Symbol Table 1158 sechdr.sh_size = I64 ? cast(uint)(elfobj.SymbolTable64.length * Elf64_Sym.sizeof) 1159 : cast(uint)(elfobj.SymbolTable.length * Elf32_Sym.sizeof); 1160 sechdr.sh_entsize = I64 ? (Elf64_Sym).sizeof : (Elf32_Sym).sizeof; 1161 sechdr.sh_link = SHN_STRINGS; 1162 sechdr.sh_info = local_cnt; 1163 foffset = elf_align(4,foffset); 1164 sechdr.sh_offset = foffset; 1165 fobjbuf.write(symtab, sechdr.sh_size); 1166 foffset += sechdr.sh_size; 1167 util_free(symtab); 1168 1169 if (shndx_data && shndx_data.length()) 1170 { 1171 assert(SecHdrTab.length >= secidx_shndx); 1172 sechdr = &SecHdrTab[secidx_shndx]; 1173 sechdr.sh_size = cast(uint)shndx_data.length(); 1174 sechdr.sh_offset = foffset; 1175 fobjbuf.write(shndx_data.buf, sechdr.sh_size); 1176 foffset += sechdr.sh_size; 1177 } 1178 1179 //dbg_printf("output section strings size 0x%x,offset 0x%x\n",symtab_strings.length(),foffset); 1180 sechdr = &SecHdrTab[SHN_STRINGS]; // Symbol Strings 1181 sechdr.sh_size = cast(uint)symtab_strings.length(); 1182 sechdr.sh_offset = foffset; 1183 fobjbuf.write(symtab_strings.buf, sechdr.sh_size); 1184 foffset += sechdr.sh_size; 1185 1186 // 1187 // Now the relocation data for program code and data sections 1188 // 1189 foffset = elf_align(4,foffset); 1190 //dbg_printf("output relocations size 0x%x, foffset 0x%x\n",section_names.length(),foffset); 1191 for (int i=1; i < SegData.length; i++) 1192 { 1193 seg = SegData[i]; 1194 if (!seg.SDbuf) 1195 { 1196 // sechdr = &SecHdrTab[seg.SDrelidx]; 1197 // if (I64 && sechdr.sh_type == SHT_RELA) 1198 // sechdr.sh_offset = foffset; 1199 continue; // 0, BSS never allocated 1200 } 1201 if (seg.SDrel && seg.SDrel.length()) 1202 { 1203 assert(seg.SDrelidx); 1204 sechdr = &SecHdrTab[seg.SDrelidx]; 1205 sechdr.sh_size = cast(uint)seg.SDrel.length(); 1206 sechdr.sh_offset = foffset; 1207 if (I64) 1208 { 1209 assert(seg.SDrelcnt == seg.SDrel.length() / Elf64_Rela.sizeof); 1210 debug 1211 { 1212 for (size_t j = 0; j < seg.SDrelcnt; ++j) 1213 { Elf64_Rela *p = (cast(Elf64_Rela *)seg.SDrel.buf) + j; 1214 if (ELF64_R_TYPE(p.r_info) == R_X86_64_64) 1215 assert(*cast(Elf64_Xword *)(seg.SDbuf.buf + p.r_offset) == 0); 1216 } 1217 } 1218 } 1219 else 1220 assert(seg.SDrelcnt == seg.SDrel.length() / Elf32_Rel.sizeof); 1221 fobjbuf.write(seg.SDrel.buf, sechdr.sh_size); 1222 foffset += sechdr.sh_size; 1223 } 1224 } 1225 1226 // 1227 // Finish off with the section header table 1228 // 1229 ulong e_shoff = foffset; // remember location in elf header 1230 //dbg_printf("output section header table\n"); 1231 1232 // Output the completed Section Header Table 1233 if (I64) 1234 { // Translate section headers to 64 bits 1235 int sz = cast(int)(SecHdrTab.length * Elf64_Shdr.sizeof); 1236 fobjbuf.reserve(sz); 1237 foreach (ref sh; SecHdrTab) 1238 { 1239 Elf64_Shdr s; 1240 s.sh_name = sh.sh_name; 1241 s.sh_type = sh.sh_type; 1242 s.sh_flags = sh.sh_flags; 1243 s.sh_addr = sh.sh_addr; 1244 s.sh_offset = sh.sh_offset; 1245 s.sh_size = sh.sh_size; 1246 s.sh_link = sh.sh_link; 1247 s.sh_info = sh.sh_info; 1248 s.sh_addralign = sh.sh_addralign; 1249 s.sh_entsize = sh.sh_entsize; 1250 fobjbuf.write((&s)[0 .. 1]); 1251 } 1252 foffset += sz; 1253 } 1254 else 1255 { 1256 fobjbuf.write(&SecHdrTab[0], cast(uint)(SecHdrTab.length * Elf32_Shdr.sizeof)); 1257 foffset += SecHdrTab.length * Elf32_Shdr.sizeof; 1258 } 1259 1260 // 1261 // Now that we have correct offset to section header table, e_shoff, 1262 // go back and re-output the elf header 1263 // 1264 ubyte ELFOSABI; 1265 switch (config.exe) 1266 { 1267 case EX_LINUX: 1268 case EX_LINUX64: 1269 ELFOSABI = ELFOSABI_LINUX; 1270 break; 1271 1272 case EX_FREEBSD: 1273 case EX_FREEBSD64: 1274 ELFOSABI = ELFOSABI_FREEBSD; 1275 break; 1276 1277 case EX_OPENBSD: 1278 case EX_OPENBSD64: 1279 ELFOSABI = ELFOSABI_OPENBSD; 1280 break; 1281 1282 case EX_SOLARIS: 1283 case EX_SOLARIS64: 1284 case EX_DRAGONFLYBSD64: 1285 ELFOSABI = ELFOSABI_SYSV; 1286 break; 1287 1288 default: 1289 assert(0); 1290 } 1291 1292 fobjbuf.position(0, hdrsize); 1293 if (I64) 1294 { 1295 __gshared Elf64_Ehdr h64 = 1296 { 1297 [ 1298 ELFMAG0,ELFMAG1,ELFMAG2,ELFMAG3, 1299 ELFCLASS64, // EI_CLASS 1300 ELFDATA2LSB, // EI_DATA 1301 EV_CURRENT, // EI_VERSION 1302 0,0, // EI_OSABI,EI_ABIVERSION 1303 0,0,0,0,0,0,0 1304 ], 1305 ET_REL, // e_type 1306 EM_X86_64, // e_machine 1307 EV_CURRENT, // e_version 1308 0, // e_entry 1309 0, // e_phoff 1310 0, // e_shoff 1311 0, // e_flags 1312 Elf64_Ehdr.sizeof, // e_ehsize 1313 Elf64_Phdr.sizeof, // e_phentsize 1314 0, // e_phnum 1315 Elf64_Shdr.sizeof, // e_shentsize 1316 0, // e_shnum 1317 SHN_SECNAMES // e_shstrndx 1318 }; 1319 h64.EHident[EI_OSABI] = ELFOSABI; 1320 h64.e_shoff = e_shoff; 1321 h64.e_shnum = e_shnum; 1322 fobjbuf.write(&h64, hdrsize); 1323 } 1324 else 1325 { 1326 __gshared Elf32_Ehdr h32 = 1327 { 1328 [ 1329 ELFMAG0,ELFMAG1,ELFMAG2,ELFMAG3, 1330 ELFCLASS32, // EI_CLASS 1331 ELFDATA2LSB, // EI_DATA 1332 EV_CURRENT, // EI_VERSION 1333 0,0, // EI_OSABI,EI_ABIVERSION 1334 0,0,0,0,0,0,0 1335 ], 1336 ET_REL, // e_type 1337 EM_386, // e_machine 1338 EV_CURRENT, // e_version 1339 0, // e_entry 1340 0, // e_phoff 1341 0, // e_shoff 1342 0, // e_flags 1343 Elf32_Ehdr.sizeof, // e_ehsize 1344 Elf32_Phdr.sizeof, // e_phentsize 1345 0, // e_phnum 1346 Elf32_Shdr.sizeof, // e_shentsize 1347 0, // e_shnum 1348 SHN_SECNAMES // e_shstrndx 1349 }; 1350 h32.EHident[EI_OSABI] = ELFOSABI; 1351 h32.e_shoff = cast(uint)e_shoff; 1352 h32.e_shnum = e_shnum; 1353 fobjbuf.write(&h32, hdrsize); 1354 } 1355 fobjbuf.position(foffset, 0); 1356 } 1357 1358 /***************************** 1359 * Line number support. 1360 */ 1361 1362 /*************************** 1363 * Record file and line number at segment and offset. 1364 * The actual .debug_line segment is put out by dwarf_termfile(). 1365 * Params: 1366 * srcpos = source file position 1367 * seg = segment it corresponds to 1368 * offset = offset within seg 1369 */ 1370 1371 void ElfObj_linnum(Srcpos srcpos, int seg, targ_size_t offset) 1372 { 1373 if (srcpos.Slinnum == 0) 1374 return; 1375 1376 static if (0) 1377 { 1378 printf("ElfObj_linnum(seg=%d, offset=0x%lx) ", seg, offset); 1379 srcpos.print(""); 1380 } 1381 1382 version (MARS) 1383 { 1384 if (!srcpos.Sfilename) 1385 return; 1386 } 1387 version (SCPP) 1388 { 1389 if (!srcpos.Sfilptr) 1390 return; 1391 sfile_debug(&srcpos_sfile(srcpos)); 1392 Sfile *sf = *srcpos.Sfilptr; 1393 } 1394 1395 size_t i; 1396 seg_data *pseg = SegData[seg]; 1397 1398 // Find entry i in SDlinnum_data[] that corresponds to srcpos filename 1399 for (i = 0; 1; i++) 1400 { 1401 if (i == pseg.SDlinnum_data.length) 1402 { // Create new entry 1403 version (MARS) 1404 pseg.SDlinnum_data.push(linnum_data(srcpos.Sfilename)); 1405 version (SCPP) 1406 pseg.SDlinnum_data.push(linnum_data(sf)); 1407 break; 1408 } 1409 version (MARS) 1410 { 1411 if (pseg.SDlinnum_data[i].filename == srcpos.Sfilename) 1412 break; 1413 } 1414 version (SCPP) 1415 { 1416 if (pseg.SDlinnum_data[i].filptr == sf) 1417 break; 1418 } 1419 } 1420 1421 linnum_data *ld = &pseg.SDlinnum_data[i]; 1422 // printf("i = %d, ld = x%x\n", i, ld); 1423 ld.linoff.push(LinOff(srcpos.Slinnum, cast(uint)offset)); 1424 } 1425 1426 1427 /******************************* 1428 * Set start address 1429 */ 1430 1431 void ElfObj_startaddress(Symbol *s) 1432 { 1433 //dbg_printf("ElfObj_startaddress(Symbol *%s)\n",s.Sident.ptr); 1434 //obj.startaddress = s; 1435 } 1436 1437 /******************************* 1438 * Output library name. 1439 */ 1440 1441 bool ElfObj_includelib(const(char)* name) 1442 { 1443 //dbg_printf("ElfObj_includelib(name *%s)\n",name); 1444 return false; 1445 } 1446 1447 /******************************* 1448 * Output linker directive. 1449 */ 1450 1451 bool ElfObj_linkerdirective(const(char)* name) 1452 { 1453 return false; 1454 } 1455 1456 /********************************** 1457 * Do we allow zero sized objects? 1458 */ 1459 1460 bool ElfObj_allowZeroSize() 1461 { 1462 return true; 1463 } 1464 1465 /************************** 1466 * Embed string in executable. 1467 */ 1468 1469 void ElfObj_exestr(const(char)* p) 1470 { 1471 //dbg_printf("ElfObj_exestr(char *%s)\n",p); 1472 } 1473 1474 /************************** 1475 * Embed string in obj. 1476 */ 1477 1478 void ElfObj_user(const(char)* p) 1479 { 1480 //dbg_printf("ElfObj_user(char *%s)\n",p); 1481 } 1482 1483 /******************************* 1484 * Output a weak extern record. 1485 */ 1486 1487 void ElfObj_wkext(Symbol *s1,Symbol *s2) 1488 { 1489 //dbg_printf("ElfObj_wkext(Symbol *%s,Symbol *s2)\n",s1.Sident.ptr,s2.Sident.ptr); 1490 } 1491 1492 /******************************* 1493 * Output file name record. 1494 * 1495 * Currently assumes that obj_filename will not be called 1496 * twice for the same file. 1497 */ 1498 1499 void ElfObj_filename(const(char)* modname) 1500 { 1501 //dbg_printf("ElfObj_filename(char *%s)\n",modname); 1502 uint strtab_idx = ElfObj_addstr(symtab_strings,modname); 1503 elf_addsym(strtab_idx,0,0,STT_FILE,STB_LOCAL,SHN_ABS); 1504 } 1505 1506 /******************************* 1507 * Embed compiler version in .obj file. 1508 */ 1509 1510 void ElfObj_compiler() 1511 { 1512 //dbg_printf("ElfObj_compiler\n"); 1513 comment_data = cast(Outbuffer*) calloc(1, Outbuffer.sizeof); 1514 assert(comment_data); 1515 1516 enum maxVersionLength = 40; // hope enough to store `git describe --dirty` 1517 enum compilerHeader = "\0Digital Mars C/C++ "; 1518 enum n = compilerHeader.length; 1519 char[n + maxVersionLength] compiler = compilerHeader; 1520 1521 assert(config._version.length + 1 < maxVersionLength); 1522 const newLength = n + config._version.length; 1523 compiler[n .. newLength] = config._version; 1524 compiler[newLength] = 0; 1525 comment_data.write(compiler[0 .. newLength + 1]); 1526 //dbg_printf("Comment data size %d\n",comment_data.length()); 1527 } 1528 1529 1530 /************************************** 1531 * Symbol is the function that calls the static constructors. 1532 * Put a pointer to it into a special segment that the startup code 1533 * looks at. 1534 * Input: 1535 * s static constructor function 1536 * dtor !=0 if leave space for static destructor 1537 * seg 1: user 1538 * 2: lib 1539 * 3: compiler 1540 */ 1541 1542 void ElfObj_staticctor(Symbol *s, int, int) 1543 { 1544 ElfObj_setModuleCtorDtor(s, true); 1545 } 1546 1547 /************************************** 1548 * Symbol is the function that calls the static destructors. 1549 * Put a pointer to it into a special segment that the exit code 1550 * looks at. 1551 * Input: 1552 * s static destructor function 1553 */ 1554 1555 void ElfObj_staticdtor(Symbol *s) 1556 { 1557 ElfObj_setModuleCtorDtor(s, false); 1558 } 1559 1560 /*************************************** 1561 * Stuff pointer to function in its own segment. 1562 * Used for static ctor and dtor lists. 1563 */ 1564 1565 void ElfObj_setModuleCtorDtor(Symbol *sfunc, bool isCtor) 1566 { 1567 IDXSEC seg; 1568 static if (USE_INIT_ARRAY) 1569 seg = isCtor ? ElfObj_getsegment(".init_array", null, SHT_INIT_ARRAY, SHF_ALLOC|SHF_WRITE, _tysize[TYnptr]) 1570 : ElfObj_getsegment(".fini_array", null, SHT_FINI_ARRAY, SHF_ALLOC|SHF_WRITE, _tysize[TYnptr]); 1571 else 1572 seg = ElfObj_getsegment(isCtor ? ".ctors" : ".dtors", null, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE, _tysize[TYnptr]); 1573 const reltype_t reltype = I64 ? R_X86_64_64 : R_386_32; 1574 const size_t sz = ElfObj_writerel(seg, cast(uint)SegData[seg].SDoffset, reltype, sfunc.Sxtrnnum, 0); 1575 SegData[seg].SDoffset += sz; 1576 } 1577 1578 1579 /*************************************** 1580 * Stuff the following data in a separate segment: 1581 * pointer to function 1582 * pointer to ehsym 1583 * length of function 1584 */ 1585 1586 void ElfObj_ehtables(Symbol *sfunc,uint size,Symbol *ehsym) 1587 { 1588 assert(0); // converted to Dwarf EH debug format 1589 } 1590 1591 /********************************************* 1592 * Don't need to generate section brackets, use __start_SEC/__stop_SEC instead. 1593 */ 1594 1595 void ElfObj_ehsections() 1596 { 1597 obj_tlssections(); 1598 } 1599 1600 /********************************************* 1601 * Put out symbols that define the beginning/end of the thread local storage sections. 1602 */ 1603 1604 private void obj_tlssections() 1605 { 1606 const align_ = I64 ? 16 : 4; 1607 1608 { 1609 const sec = ElfObj_getsegment(".tdata", null, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, align_); 1610 ElfObj_bytes(sec, 0, align_, null); 1611 1612 const namidx = ElfObj_addstr(symtab_strings,"_tlsstart"); 1613 elf_addsym(namidx, 0, align_, STT_TLS, STB_GLOBAL, MAP_SEG2SECIDX(sec)); 1614 } 1615 1616 ElfObj_getsegment(".tdata.", null, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, align_); 1617 1618 { 1619 const sec = ElfObj_getsegment(".tcommon", null, SHT_NOBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, align_); 1620 const namidx = ElfObj_addstr(symtab_strings,"_tlsend"); 1621 elf_addsym(namidx, 0, align_, STT_TLS, STB_GLOBAL, MAP_SEG2SECIDX(sec)); 1622 } 1623 } 1624 1625 /********************************* 1626 * Setup for Symbol s to go into a COMDAT segment. 1627 * Output (if s is a function): 1628 * cseg segment index of new current code segment 1629 * Offset(cseg) starting offset in cseg 1630 * Returns: 1631 * "segment index" of COMDAT 1632 * References: 1633 * Section Groups http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html#section_groups 1634 * COMDAT section groups https://www.airs.com/blog/archives/52 1635 */ 1636 1637 private void setup_comdat(Symbol *s) 1638 { 1639 const(char)* prefix; 1640 int type; 1641 int flags; 1642 int align_ = 4; 1643 1644 //printf("ElfObj_comdat(Symbol *%s\n",s.Sident.ptr); 1645 //symbol_print(s); 1646 symbol_debug(s); 1647 if (tyfunc(s.ty())) 1648 { 1649 static if (!ELF_COMDAT) 1650 { 1651 prefix = ".text."; // undocumented, but works 1652 type = SHT_PROGBITS; 1653 flags = SHF_ALLOC|SHF_EXECINSTR; 1654 } 1655 else 1656 { 1657 elfobj.resetSyms.push(s); 1658 1659 const(char)* p = cpp_mangle2(s); 1660 1661 bool added = false; 1662 Pair* pidx = elf_addsectionname(".text.", p, &added); 1663 int groupseg; 1664 if (added) 1665 { 1666 // Create a new COMDAT section group 1667 Pair* pidx2 = elf_addsectionname(".group"); 1668 groupseg = elf_addsegment(pidx2.start, SHT_GROUP, 0, (IDXSYM).sizeof); 1669 MAP_SEG2SEC(groupseg).sh_link = SHN_SYMTAB; 1670 MAP_SEG2SEC(groupseg).sh_entsize = (IDXSYM).sizeof; 1671 // Create a new TEXT section for the comdat symbol with the SHF_GROUP bit set 1672 s.Sseg = elf_addsegment(pidx.start, SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR|SHF_GROUP, align_); 1673 // add TEXT section to COMDAT section group 1674 SegData[groupseg].SDbuf.write32(GRP_COMDAT); 1675 SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(s.Sseg)); 1676 SegData[s.Sseg].SDassocseg = groupseg; 1677 } 1678 else 1679 { 1680 /* If the section already existed, we've hit one of the few 1681 * occurences of different symbols with identical mangling. This should 1682 * not happen, but as a workaround we just use the existing sections. 1683 * Also see https://issues.dlang.org/show_bug.cgi?id=17352, 1684 * https://issues.dlang.org/show_bug.cgi?id=14831, and 1685 * https://issues.dlang.org/show_bug.cgi?id=17339. 1686 */ 1687 if (!pidx.end) 1688 pidx.end = elf_getsegment(pidx.start); 1689 s.Sseg = pidx.end; 1690 groupseg = SegData[s.Sseg].SDassocseg; 1691 assert(groupseg); 1692 } 1693 1694 // Create a weak symbol for the comdat 1695 const namidxcd = ElfObj_addstr(symtab_strings, p); 1696 s.Sxtrnnum = elf_addsym(namidxcd, 0, 0, STT_FUNC, STB_WEAK, MAP_SEG2SECIDX(s.Sseg)); 1697 1698 if (added) 1699 { 1700 /* Set the weak symbol as comdat group symbol. This symbol determines 1701 * whether all or none of the sections in the group get linked. It's 1702 * also the only symbol in all group sections that might be referenced 1703 * from outside of the group. 1704 */ 1705 MAP_SEG2SEC(groupseg).sh_info = s.Sxtrnnum; 1706 SegData[s.Sseg].SDsym = s; 1707 } 1708 else 1709 { 1710 // existing group symbol, and section symbol 1711 assert(MAP_SEG2SEC(groupseg).sh_info); 1712 assert(MAP_SEG2SEC(groupseg).sh_info == SegData[s.Sseg].SDsym.Sxtrnnum); 1713 } 1714 if (s.Salignment > align_) 1715 SegData[s.Sseg].SDalignment = s.Salignment; 1716 return; 1717 } 1718 } 1719 else if ((s.ty() & mTYLINK) == mTYthread) 1720 { 1721 /* Ensure that ".tdata" precedes any other .tdata. section, as the ld 1722 * linker script fails to work right. 1723 */ 1724 if (I64) 1725 align_ = 16; 1726 ElfObj_getsegment(".tdata", null, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, align_); 1727 1728 s.Sfl = FLtlsdata; 1729 prefix = ".tdata."; 1730 type = SHT_PROGBITS; 1731 flags = SHF_ALLOC|SHF_WRITE|SHF_TLS; 1732 } 1733 else 1734 { 1735 if (I64) 1736 align_ = 16; 1737 s.Sfl = FLdata; 1738 //prefix = ".gnu.linkonce.d."; 1739 prefix = ".data."; 1740 type = SHT_PROGBITS; 1741 flags = SHF_ALLOC|SHF_WRITE; 1742 } 1743 1744 s.Sseg = ElfObj_getsegment(prefix, cpp_mangle2(s), type, flags, align_); 1745 // find or create new segment 1746 if (s.Salignment > align_) 1747 SegData[s.Sseg].SDalignment = s.Salignment; 1748 SegData[s.Sseg].SDsym = s; 1749 } 1750 1751 int ElfObj_comdat(Symbol *s) 1752 { 1753 setup_comdat(s); 1754 if (s.Sfl == FLdata || s.Sfl == FLtlsdata) 1755 { 1756 ElfObj_pubdef(s.Sseg,s,0); 1757 searchfixlist(s); // backpatch any refs to this symbol 1758 } 1759 return s.Sseg; 1760 } 1761 1762 int ElfObj_comdatsize(Symbol *s, targ_size_t symsize) 1763 { 1764 setup_comdat(s); 1765 if (s.Sfl == FLdata || s.Sfl == FLtlsdata) 1766 { 1767 ElfObj_pubdefsize(s.Sseg,s,0,symsize); 1768 searchfixlist(s); // backpatch any refs to this symbol 1769 } 1770 s.Soffset = 0; 1771 return s.Sseg; 1772 } 1773 1774 int ElfObj_readonly_comdat(Symbol *s) 1775 { 1776 assert(0); 1777 } 1778 1779 int ElfObj_jmpTableSegment(Symbol *s) 1780 { 1781 segidx_t seg = jmpseg; 1782 if (seg) // memoize the jmpseg on a per-function basis 1783 return seg; 1784 1785 if (config.flags & CFGromable) 1786 seg = cseg; 1787 else 1788 { 1789 seg_data *pseg = SegData[s.Sseg]; 1790 if (pseg.SDassocseg) 1791 { 1792 /* `s` is in a COMDAT, so the jmp table segment must also 1793 * go into its own segment in the same group. 1794 */ 1795 seg = ElfObj_getsegment(".rodata.", s.Sident.ptr, SHT_PROGBITS, SHF_ALLOC|SHF_GROUP, _tysize[TYnptr]); 1796 addSegmentToComdat(seg, s.Sseg); 1797 } 1798 else 1799 seg = CDATA; 1800 } 1801 jmpseg = seg; 1802 return seg; 1803 } 1804 1805 /**************************************** 1806 * If `comdatseg` has a group, add `secidx` to the group. 1807 * Params: 1808 * secidx = section to add to the group 1809 * comdatseg = comdat that started the group 1810 */ 1811 1812 private void addSectionToComdat(IDXSEC secidx, segidx_t comdatseg) 1813 { 1814 seg_data *pseg = SegData[comdatseg]; 1815 segidx_t groupseg = pseg.SDassocseg; 1816 if (groupseg) 1817 { 1818 seg_data *pgroupseg = SegData[groupseg]; 1819 1820 /* Don't write it if it is already there 1821 */ 1822 Outbuffer *buf = pgroupseg.SDbuf; 1823 assert(int.sizeof == 4); // loop depends on this 1824 for (size_t i = buf.length(); i > 4;) 1825 { 1826 /* A linear search, but shouldn't be more than 4 items 1827 * in it. 1828 */ 1829 i -= 4; 1830 if (*cast(int*)(buf.buf + i) == secidx) 1831 return; 1832 } 1833 buf.write32(secidx); 1834 } 1835 } 1836 1837 /*********************************** 1838 * Returns: 1839 * jump table segment for function s 1840 */ 1841 void addSegmentToComdat(segidx_t seg, segidx_t comdatseg) 1842 { 1843 addSectionToComdat(SegData[seg].SDshtidx, comdatseg); 1844 } 1845 1846 private segidx_t elf_addsegment2(IDXSEC shtidx, IDXSYM symidx, IDXSEC relidx) 1847 { 1848 //printf("SegData = %p\n", SegData); 1849 const segidx_t seg = cast(segidx_t)SegData.length; 1850 seg_data** ppseg = SegData.push(); 1851 1852 seg_data* pseg = *ppseg; 1853 if (!pseg) 1854 { 1855 pseg = cast(seg_data *)mem_calloc(seg_data.sizeof); 1856 //printf("test2: SegData[%d] = %p\n", seg, SegData[seg]); 1857 SegData[seg] = pseg; 1858 } 1859 else 1860 memset(pseg, 0, seg_data.sizeof); 1861 1862 pseg.SDseg = seg; 1863 pseg.SDshtidx = shtidx; 1864 pseg.SDoffset = 0; 1865 if (pseg.SDbuf) 1866 pseg.SDbuf.reset(); 1867 else 1868 { if (SecHdrTab[shtidx].sh_type != SHT_NOBITS) 1869 { 1870 pseg.SDbuf = cast(Outbuffer*) calloc(1, (Outbuffer).sizeof); 1871 assert(pseg.SDbuf); 1872 pseg.SDbuf.reserve(1024); 1873 } 1874 } 1875 if (pseg.SDrel) 1876 pseg.SDrel.reset(); 1877 pseg.SDsymidx = symidx; 1878 pseg.SDrelidx = relidx; 1879 pseg.SDrelmaxoff = 0; 1880 pseg.SDrelindex = 0; 1881 pseg.SDrelcnt = 0; 1882 pseg.SDshtidxout = 0; 1883 pseg.SDsym = null; 1884 pseg.SDaranges_offset = 0; 1885 pseg.SDlinnum_data.reset(); 1886 return seg; 1887 } 1888 1889 /******************************** 1890 * Add a new section and get corresponding seg_data entry. 1891 * 1892 * Input: 1893 * nameidx = string index of section name 1894 * type = section header type, e.g. SHT_PROGBITS 1895 * flags = section header flags, e.g. SHF_ALLOC 1896 * align_ = section alignment 1897 * Returns: 1898 * SegData index of newly created section. 1899 */ 1900 private segidx_t elf_addsegment(IDXSTR namidx, int type, int flags, int align_) 1901 { 1902 //dbg_printf("\tNew segment - %d size %d\n", seg,SegData[seg].SDbuf); 1903 IDXSEC shtidx = elf_newsection2(namidx,type,flags,0,0,0,0,0,0,0); 1904 SecHdrTab[shtidx].sh_addralign = align_; 1905 IDXSYM symidx = elf_addsym(0, 0, 0, STT_SECTION, STB_LOCAL, shtidx); 1906 segidx_t seg = elf_addsegment2(shtidx, symidx, 0); 1907 //printf("-ElfObj_getsegment() = %d\n", seg); 1908 return seg; 1909 } 1910 1911 /******************************** 1912 * Find corresponding seg_data entry for existing section. 1913 * 1914 * Input: 1915 * nameidx = string index of section name 1916 * Returns: 1917 * SegData index of found section or 0 if none was found. 1918 */ 1919 private int elf_getsegment(IDXSTR namidx) 1920 { 1921 // find existing section 1922 for (int seg = CODE; seg < SegData.length; seg++) 1923 { // should be in segment table 1924 if (MAP_SEG2SEC(seg).sh_name == namidx) 1925 { 1926 return seg; // found section for segment 1927 } 1928 } 1929 return 0; 1930 } 1931 1932 /******************************** 1933 * Get corresponding seg_data entry for an existing or newly added section. 1934 * 1935 * Input: 1936 * name = name of section 1937 * suffix = append to name 1938 * type = section header type, e.g. SHT_PROGBITS 1939 * flags = section header flags, e.g. SHF_ALLOC 1940 * align_ = section alignment 1941 * Returns: 1942 * SegData index of found or newly created section. 1943 */ 1944 segidx_t ElfObj_getsegment(const(char)* name, const(char)* suffix, int type, int flags, 1945 int align_) 1946 { 1947 //printf("ElfObj_getsegment(%s,%s,flags %x, align_ %d)\n",name,suffix,flags,align_); 1948 bool added = false; 1949 Pair* pidx = elf_addsectionname(name, suffix, &added); 1950 if (!added) 1951 { 1952 // Existing segment 1953 if (!pidx.end) 1954 pidx.end = elf_getsegment(pidx.start); 1955 return pidx.end; 1956 } 1957 else 1958 // New segment, cache the segment index in the hash table 1959 pidx.end = elf_addsegment(pidx.start, type, flags, align_); 1960 return pidx.end; 1961 } 1962 1963 /********************************** 1964 * Reset code seg to existing seg. 1965 * Used after a COMDAT for a function is done. 1966 */ 1967 1968 void ElfObj_setcodeseg(int seg) 1969 { 1970 cseg = seg; 1971 } 1972 1973 /******************************** 1974 * Define a new code segment. 1975 * Input: 1976 * name name of segment, if null then revert to default 1977 * suffix 0 use name as is 1978 * 1 append "_TEXT" to name 1979 * Output: 1980 * cseg segment index of new current code segment 1981 * Offset(cseg) starting offset in cseg 1982 * Returns: 1983 * segment index of newly created code segment 1984 */ 1985 1986 int ElfObj_codeseg(const char *name,int suffix) 1987 { 1988 int seg; 1989 const(char)* sfx; 1990 1991 //dbg_printf("ElfObj_codeseg(%s,%x)\n",name,suffix); 1992 1993 sfx = (suffix) ? "_TEXT".ptr : null; 1994 1995 if (!name) // returning to default code segment 1996 { 1997 if (cseg != CODE) // not the current default 1998 { 1999 SegData[cseg].SDoffset = Offset(cseg); 2000 Offset(cseg) = SegData[CODE].SDoffset; 2001 cseg = CODE; 2002 } 2003 return cseg; 2004 } 2005 2006 seg = ElfObj_getsegment(name, sfx, SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 4); 2007 // find or create code segment 2008 2009 cseg = seg; // new code segment index 2010 Offset(cseg) = 0; 2011 2012 return seg; 2013 } 2014 2015 /********************************* 2016 * Define segments for Thread Local Storage. 2017 * Here's what the elf tls spec says: 2018 * Field .tbss .tdata 2019 * sh_name .tbss .tdata 2020 * sh_type SHT_NOBITS SHT_PROGBITS 2021 * sh_flags SHF_ALLOC|SHF_WRITE| SHF_ALLOC|SHF_WRITE| 2022 * SHF_TLS SHF_TLS 2023 * sh_addr virtual addr of section virtual addr of section 2024 * sh_offset 0 file offset of initialization image 2025 * sh_size size of section size of section 2026 * sh_link SHN_UNDEF SHN_UNDEF 2027 * sh_info 0 0 2028 * sh_addralign alignment of section alignment of section 2029 * sh_entsize 0 0 2030 * We want _tlsstart and _tlsend to bracket all the D tls data. 2031 * The default linker script (ld -verbose) says: 2032 * .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } 2033 * .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } 2034 * so if we assign names: 2035 * _tlsstart .tdata 2036 * symbols .tdata. 2037 * symbols .tbss 2038 * _tlsend .tbss. 2039 * this should work. 2040 * Don't care about sections emitted by other languages, as we presume they 2041 * won't be storing D gc roots in their tls. 2042 * Output: 2043 * seg_tlsseg set to segment number for TLS segment. 2044 * Returns: 2045 * segment for TLS segment 2046 */ 2047 2048 seg_data *ElfObj_tlsseg() 2049 { 2050 /* Ensure that ".tdata" precedes any other .tdata. section, as the ld 2051 * linker script fails to work right. 2052 */ 2053 ElfObj_getsegment(".tdata", null, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, 4); 2054 2055 static immutable char[8] tlssegname = ".tdata."; 2056 //dbg_printf("ElfObj_tlsseg(\n"); 2057 2058 if (seg_tlsseg == UNKNOWN) 2059 { 2060 seg_tlsseg = ElfObj_getsegment(tlssegname.ptr, null, SHT_PROGBITS, 2061 SHF_ALLOC|SHF_WRITE|SHF_TLS, I64 ? 16 : 4); 2062 } 2063 return SegData[seg_tlsseg]; 2064 } 2065 2066 2067 /********************************* 2068 * Define segments for Thread Local Storage. 2069 * Output: 2070 * seg_tlsseg_bss set to segment number for TLS segment. 2071 * Returns: 2072 * segment for TLS segment 2073 */ 2074 2075 seg_data *ElfObj_tlsseg_bss() 2076 { 2077 static immutable char[6] tlssegname = ".tbss"; 2078 //dbg_printf("ElfObj_tlsseg_bss(\n"); 2079 2080 if (seg_tlsseg_bss == UNKNOWN) 2081 { 2082 seg_tlsseg_bss = ElfObj_getsegment(tlssegname.ptr, null, SHT_NOBITS, 2083 SHF_ALLOC|SHF_WRITE|SHF_TLS, I64 ? 16 : 4); 2084 } 2085 return SegData[seg_tlsseg_bss]; 2086 } 2087 2088 seg_data *ElfObj_tlsseg_data() 2089 { 2090 // specific for Mach-O 2091 assert(0); 2092 } 2093 2094 2095 /******************************* 2096 * Output an alias definition record. 2097 */ 2098 2099 void ElfObj_alias(const(char)* n1,const(char)* n2) 2100 { 2101 //printf("ElfObj_alias(%s,%s)\n",n1,n2); 2102 assert(0); 2103 static if (0) 2104 { 2105 char *buffer = cast(char *) alloca(strlen(n1) + strlen(n2) + 2 * ONS_OHD); 2106 uint len = obj_namestring(buffer,n1); 2107 len += obj_namestring(buffer + len,n2); 2108 objrecord(ALIAS,buffer,len); 2109 } 2110 } 2111 2112 private extern (D) char* unsstr(uint value) 2113 { 2114 __gshared char[64] buffer = void; 2115 2116 sprintf(buffer.ptr, "%d", value); 2117 return buffer.ptr; 2118 } 2119 2120 /******************************* 2121 * Mangle a name. 2122 * Returns: 2123 * mangled name 2124 */ 2125 2126 private extern (D) 2127 char *obj_mangle2(Symbol *s,char *dest, size_t *destlen) 2128 { 2129 char *name; 2130 2131 //dbg_printf("ElfObj_mangle('%s'), mangle = x%x\n",s.Sident.ptr,type_mangle(s.Stype)); 2132 symbol_debug(s); 2133 assert(dest); 2134 2135 version (SCPP) 2136 name = CPP ? cpp_mangle2(s) : s.Sident.ptr; 2137 else version (MARS) 2138 // C++ name mangling is handled by front end 2139 name = s.Sident.ptr; 2140 else 2141 name = s.Sident.ptr; 2142 2143 size_t len = strlen(name); // # of bytes in name 2144 //dbg_printf("len %d\n",len); 2145 switch (type_mangle(s.Stype)) 2146 { 2147 case mTYman_pas: // if upper case 2148 case mTYman_for: 2149 if (len >= DEST_LEN) 2150 dest = cast(char *)mem_malloc(len + 1); 2151 memcpy(dest,name,len + 1); // copy in name and ending 0 2152 for (int i = 0; 1; i++) 2153 { char c = dest[i]; 2154 if (!c) 2155 break; 2156 if (c >= 'a' && c <= 'z') 2157 dest[i] = cast(char)(c + 'A' - 'a'); 2158 } 2159 break; 2160 case mTYman_std: 2161 { 2162 bool cond = (tyfunc(s.ty()) && !variadic(s.Stype)); 2163 if (cond) 2164 { 2165 char *pstr = unsstr(type_paramsize(s.Stype)); 2166 size_t pstrlen = strlen(pstr); 2167 size_t dlen = len + 1 + pstrlen; 2168 2169 if (dlen >= DEST_LEN) 2170 dest = cast(char *)mem_malloc(dlen + 1); 2171 memcpy(dest,name,len); 2172 dest[len] = '@'; 2173 memcpy(dest + 1 + len, pstr, pstrlen + 1); 2174 len = dlen; 2175 break; 2176 } 2177 } 2178 goto case; 2179 2180 case mTYman_cpp: 2181 case mTYman_c: 2182 case mTYman_d: 2183 case mTYman_sys: 2184 case 0: 2185 if (len >= DEST_LEN) 2186 dest = cast(char *)mem_malloc(len + 1); 2187 memcpy(dest,name,len+1);// copy in name and trailing 0 2188 break; 2189 2190 default: 2191 debug 2192 { 2193 printf("mangling %x\n",type_mangle(s.Stype)); 2194 symbol_print(s); 2195 } 2196 printf("%d\n", type_mangle(s.Stype)); 2197 assert(0); 2198 } 2199 //dbg_printf("\t %s\n",dest); 2200 *destlen = len; 2201 return dest; 2202 } 2203 2204 /******************************* 2205 * Export a function name. 2206 */ 2207 2208 void ElfObj_export_symbol(Symbol *s,uint argsize) 2209 { 2210 //dbg_printf("ElfObj_export_symbol(%s,%d)\n",s.Sident.ptr,argsize); 2211 } 2212 2213 /******************************* 2214 * Update data information about symbol 2215 * align for output and assign segment 2216 * if not already specified. 2217 * 2218 * Input: 2219 * sdata data symbol 2220 * datasize output size 2221 * seg default seg if not known 2222 * Returns: 2223 * actual seg 2224 */ 2225 2226 int ElfObj_data_start(Symbol *sdata, targ_size_t datasize, int seg) 2227 { 2228 targ_size_t alignbytes; 2229 //printf("ElfObj_data_start(%s,size %llx,seg %d)\n",sdata.Sident.ptr,datasize,seg); 2230 //symbol_print(sdata); 2231 2232 if (sdata.Sseg == UNKNOWN) // if we don't know then there 2233 sdata.Sseg = seg; // wasn't any segment override 2234 else 2235 seg = sdata.Sseg; 2236 targ_size_t offset = Offset(seg); 2237 if (sdata.Salignment > 0) 2238 { if (SegData[seg].SDalignment < sdata.Salignment) 2239 SegData[seg].SDalignment = sdata.Salignment; 2240 alignbytes = ((offset + sdata.Salignment - 1) & ~(sdata.Salignment - 1)) - offset; 2241 } 2242 else 2243 alignbytes = _align(datasize, offset) - offset; 2244 if (alignbytes) 2245 ElfObj_lidata(seg, offset, alignbytes); 2246 sdata.Soffset = offset + alignbytes; 2247 return seg; 2248 } 2249 2250 /******************************* 2251 * Update function info before codgen 2252 * 2253 * If code for this function is in a different segment 2254 * than the current default in cseg, switch cseg to new segment. 2255 */ 2256 2257 void ElfObj_func_start(Symbol *sfunc) 2258 { 2259 //dbg_printf("ElfObj_func_start(%s)\n",sfunc.Sident.ptr); 2260 symbol_debug(sfunc); 2261 2262 if ((tybasic(sfunc.ty()) == TYmfunc) && (sfunc.Sclass == SCextern)) 2263 { // create a new code segment 2264 sfunc.Sseg = 2265 ElfObj_getsegment(".gnu.linkonce.t.", cpp_mangle2(sfunc), SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR,4); 2266 2267 } 2268 else if (sfunc.Sseg == UNKNOWN) 2269 sfunc.Sseg = CODE; 2270 //dbg_printf("sfunc.Sseg %d CODE %d cseg %d Coffset %d\n",sfunc.Sseg,CODE,cseg,Offset(cseg)); 2271 cseg = sfunc.Sseg; 2272 jmpseg = 0; // only 1 jmp seg per function 2273 assert(cseg == CODE || cseg > COMD); 2274 static if (ELF_COMDAT) 2275 { 2276 if (!symbol_iscomdat2(sfunc)) 2277 { 2278 ElfObj_pubdef(cseg, sfunc, Offset(cseg)); 2279 } 2280 } 2281 else 2282 { 2283 ElfObj_pubdef(cseg, sfunc, Offset(cseg)); 2284 } 2285 sfunc.Soffset = Offset(cseg); 2286 2287 dwarf_func_start(sfunc); 2288 } 2289 2290 /******************************* 2291 * Update function info after codgen 2292 */ 2293 2294 void ElfObj_func_term(Symbol *sfunc) 2295 { 2296 //dbg_printf("ElfObj_func_term(%s) offset %x, Coffset %x symidx %d\n", 2297 // sfunc.Sident.ptr, sfunc.Soffset,Offset(cseg),sfunc.Sxtrnnum); 2298 2299 // fill in the function size 2300 if (I64) 2301 elfobj.SymbolTable64[sfunc.Sxtrnnum].st_size = Offset(cseg) - sfunc.Soffset; 2302 else 2303 elfobj.SymbolTable[sfunc.Sxtrnnum].st_size = cast(uint)(Offset(cseg) - sfunc.Soffset); 2304 dwarf_func_term(sfunc); 2305 } 2306 2307 /******************************** 2308 * Output a public definition. 2309 * Input: 2310 * seg = segment index that symbol is defined in 2311 * s . symbol 2312 * offset = offset of name within segment 2313 */ 2314 2315 void ElfObj_pubdef(int seg, Symbol *s, targ_size_t offset) 2316 { 2317 const targ_size_t symsize= 2318 tyfunc(s.ty()) ? Offset(s.Sseg) - offset : type_size(s.Stype); 2319 ElfObj_pubdefsize(seg, s, offset, symsize); 2320 } 2321 2322 /******************************** 2323 * Output a public definition. 2324 * Input: 2325 * seg = segment index that symbol is defined in 2326 * s . symbol 2327 * offset = offset of name within segment 2328 * symsize size of symbol 2329 */ 2330 2331 void ElfObj_pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize) 2332 { 2333 int bind; 2334 ubyte visibility = STV_DEFAULT; 2335 switch (s.Sclass) 2336 { 2337 case SCglobal: 2338 case SCinline: 2339 bind = STB_GLOBAL; 2340 break; 2341 case SCcomdat: 2342 case SCcomdef: 2343 bind = STB_WEAK; 2344 break; 2345 case SCstatic: 2346 if (s.Sflags & SFLhidden) 2347 { 2348 visibility = STV_HIDDEN; 2349 bind = STB_GLOBAL; 2350 break; 2351 } 2352 goto default; 2353 2354 default: 2355 bind = STB_LOCAL; 2356 break; 2357 } 2358 2359 //printf("\nElfObj_pubdef(%d,%s,%d)\n",seg,s.Sident.ptr,offset); 2360 //symbol_print(s); 2361 2362 symbol_debug(s); 2363 elfobj.resetSyms.push(s); 2364 const namidx = elf_addmangled(s); 2365 //printf("\tnamidx %d,section %d\n",namidx,MAP_SEG2SECIDX(seg)); 2366 if (tyfunc(s.ty())) 2367 { 2368 s.Sxtrnnum = elf_addsym(namidx, offset, cast(uint)symsize, 2369 STT_FUNC, bind, MAP_SEG2SECIDX(seg), visibility); 2370 } 2371 else 2372 { 2373 const uint typ = (s.ty() & mTYthread) ? STT_TLS : STT_OBJECT; 2374 s.Sxtrnnum = elf_addsym(namidx, offset, cast(uint)symsize, 2375 typ, bind, MAP_SEG2SECIDX(seg), visibility); 2376 } 2377 } 2378 2379 /******************************* 2380 * Output an external symbol for name. 2381 * Input: 2382 * name Name to do EXTDEF on 2383 * (Not to be mangled) 2384 * Returns: 2385 * Symbol table index of the definition 2386 * NOTE: Numbers will not be linear. 2387 */ 2388 2389 int ElfObj_external_def(const(char)* name) 2390 { 2391 //dbg_printf("ElfObj_external_def('%s')\n",name); 2392 assert(name); 2393 const namidx = ElfObj_addstr(symtab_strings,name); 2394 const symidx = elf_addsym(namidx, 0, 0, STT_NOTYPE, STB_GLOBAL, SHN_UNDEF); 2395 return symidx; 2396 } 2397 2398 2399 /******************************* 2400 * Output an external for existing symbol. 2401 * Input: 2402 * s Symbol to do EXTDEF on 2403 * (Name is to be mangled) 2404 * Returns: 2405 * Symbol table index of the definition 2406 * NOTE: Numbers will not be linear. 2407 */ 2408 2409 int ElfObj_external(Symbol *s) 2410 { 2411 int symtype,sectype; 2412 uint size; 2413 2414 //dbg_printf("ElfObj_external('%s') %x\n",s.Sident.ptr,s.Svalue); 2415 symbol_debug(s); 2416 elfobj.resetSyms.push(s); 2417 const namidx = elf_addmangled(s); 2418 2419 version (SCPP) 2420 { 2421 if (s.Sscope && !tyfunc(s.ty())) 2422 { 2423 symtype = STT_OBJECT; 2424 sectype = SHN_COMMON; 2425 size = type_size(s.Stype); 2426 } 2427 else 2428 { 2429 symtype = STT_NOTYPE; 2430 sectype = SHN_UNDEF; 2431 size = 0; 2432 } 2433 } 2434 else 2435 { 2436 symtype = STT_NOTYPE; 2437 sectype = SHN_UNDEF; 2438 size = 0; 2439 } 2440 if (s.ty() & mTYthread) 2441 { 2442 //printf("ElfObj_external('%s') %x TLS\n",s.Sident.ptr,s.Svalue); 2443 symtype = STT_TLS; 2444 } 2445 2446 s.Sxtrnnum = elf_addsym(namidx, size, size, symtype, 2447 /*(s.ty() & mTYweak) ? STB_WEAK : */STB_GLOBAL, sectype); 2448 return s.Sxtrnnum; 2449 2450 } 2451 2452 /******************************* 2453 * Output a common block definition. 2454 * Input: 2455 * p . external identifier 2456 * size size in bytes of each elem 2457 * count number of elems 2458 * Returns: 2459 * Symbol table index for symbol 2460 */ 2461 2462 int ElfObj_common_block(Symbol *s,targ_size_t size,targ_size_t count) 2463 { 2464 //printf("ElfObj_common_block('%s',%d,%d)\n",s.Sident.ptr,size,count); 2465 symbol_debug(s); 2466 2467 int align_ = I64 ? 16 : 4; 2468 if (s.ty() & mTYthread) 2469 { 2470 s.Sseg = ElfObj_getsegment(".tbss.", cpp_mangle2(s), 2471 SHT_NOBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, align_); 2472 s.Sfl = FLtlsdata; 2473 SegData[s.Sseg].SDsym = s; 2474 SegData[s.Sseg].SDoffset += size * count; 2475 ElfObj_pubdefsize(s.Sseg, s, 0, size * count); 2476 searchfixlist(s); 2477 return s.Sseg; 2478 } 2479 else 2480 { 2481 s.Sseg = ElfObj_getsegment(".bss.", cpp_mangle2(s), 2482 SHT_NOBITS, SHF_ALLOC|SHF_WRITE, align_); 2483 s.Sfl = FLudata; 2484 SegData[s.Sseg].SDsym = s; 2485 SegData[s.Sseg].SDoffset += size * count; 2486 ElfObj_pubdefsize(s.Sseg, s, 0, size * count); 2487 searchfixlist(s); 2488 return s.Sseg; 2489 } 2490 static if (0) 2491 { 2492 elfobj.resetSyms.push(s); 2493 const namidx = elf_addmangled(s); 2494 alignOffset(UDATA,size); 2495 const symidx = elf_addsym(namidx, SegData[UDATA].SDoffset, size*count, 2496 (s.ty() & mTYthread) ? STT_TLS : STT_OBJECT, 2497 STB_WEAK, SHN_BSS); 2498 //dbg_printf("\tElfObj_common_block returning symidx %d\n",symidx); 2499 s.Sseg = UDATA; 2500 s.Sfl = FLudata; 2501 SegData[UDATA].SDoffset += size * count; 2502 return symidx; 2503 } 2504 } 2505 2506 int ElfObj_common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count) 2507 { 2508 return ElfObj_common_block(s, size, count); 2509 } 2510 2511 /*************************************** 2512 * Append an iterated data block of 0s. 2513 * (uninitialized data only) 2514 */ 2515 2516 void ElfObj_write_zeros(seg_data *pseg, targ_size_t count) 2517 { 2518 ElfObj_lidata(pseg.SDseg, pseg.SDoffset, count); 2519 } 2520 2521 /*************************************** 2522 * Output an iterated data block of 0s. 2523 * 2524 * For boundary alignment and initialization 2525 */ 2526 2527 void ElfObj_lidata(int seg,targ_size_t offset,targ_size_t count) 2528 { 2529 //printf("ElfObj_lidata(%d,%x,%d)\n",seg,offset,count); 2530 if (seg == UDATA || seg == UNKNOWN) 2531 { // Use SDoffset to record size of .BSS section 2532 SegData[UDATA].SDoffset += count; 2533 } 2534 else if (MAP_SEG2SEC(seg).sh_type == SHT_NOBITS) 2535 { // Use SDoffset to record size of .TBSS section 2536 SegData[seg].SDoffset += count; 2537 } 2538 else 2539 { 2540 ElfObj_bytes(seg, offset, cast(uint)count, null); 2541 } 2542 } 2543 2544 /*********************************** 2545 * Append byte to segment. 2546 */ 2547 2548 void ElfObj_write_byte(seg_data *pseg, uint byte_) 2549 { 2550 ElfObj_byte(pseg.SDseg, pseg.SDoffset, byte_); 2551 } 2552 2553 /************************************ 2554 * Output byte to object file. 2555 */ 2556 2557 void ElfObj_byte(int seg,targ_size_t offset,uint byte_) 2558 { 2559 Outbuffer *buf = SegData[seg].SDbuf; 2560 int save = cast(int)buf.length(); 2561 //dbg_printf("ElfObj_byte(seg=%d, offset=x%lx, byte_=x%x)\n",seg,offset,byte_); 2562 buf.setsize(cast(uint)offset); 2563 buf.writeByte(byte_); 2564 if (save > offset+1) 2565 buf.setsize(save); 2566 else 2567 SegData[seg].SDoffset = offset+1; 2568 //dbg_printf("\tsize now %d\n",buf.length()); 2569 } 2570 2571 /*********************************** 2572 * Append bytes to segment. 2573 */ 2574 2575 void ElfObj_write_bytes(seg_data *pseg, uint nbytes, void *p) 2576 { 2577 ElfObj_bytes(pseg.SDseg, pseg.SDoffset, nbytes, p); 2578 } 2579 2580 /************************************ 2581 * Output bytes to object file. 2582 * Returns: 2583 * nbytes 2584 */ 2585 2586 uint ElfObj_bytes(int seg, targ_size_t offset, uint nbytes, void *p) 2587 { 2588 static if (0) 2589 { 2590 if (!(seg >= 0 && seg < SegData.length)) 2591 { printf("ElfObj_bytes: seg = %d, SegData.length = %d\n", seg, SegData.length); 2592 *cast(char*)0=0; 2593 } 2594 } 2595 assert(seg >= 0 && seg < SegData.length); 2596 Outbuffer *buf = SegData[seg].SDbuf; 2597 if (buf == null) 2598 { 2599 //dbg_printf("ElfObj_bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n", seg, offset, nbytes, p); 2600 //raise(SIGSEGV); 2601 assert(buf != null); 2602 } 2603 int save = cast(int)buf.length(); 2604 //dbg_printf("ElfObj_bytes(seg=%d, offset=x%lx, nbytes=%d, p=x%x)\n", 2605 //seg,offset,nbytes,p); 2606 buf.position(cast(size_t)offset, nbytes); 2607 if (p) 2608 buf.writen(p, nbytes); 2609 else // Zero out the bytes 2610 buf.writezeros(nbytes); 2611 2612 if (save > offset+nbytes) 2613 buf.setsize(save); 2614 else 2615 SegData[seg].SDoffset = offset+nbytes; 2616 return nbytes; 2617 } 2618 2619 /******************************* 2620 * Output a relocation entry for a segment 2621 * Input: 2622 * seg = where the address is going 2623 * offset = offset within seg 2624 * type = ELF relocation type R_ARCH_XXXX 2625 * index = Related symbol table index 2626 * val = addend or displacement from address 2627 */ 2628 2629 __gshared int relcnt=0; 2630 2631 void ElfObj_addrel(int seg, targ_size_t offset, uint type, 2632 IDXSYM symidx, targ_size_t val) 2633 { 2634 seg_data *segdata; 2635 Outbuffer *buf; 2636 IDXSEC secidx; 2637 2638 //assert(val == 0); 2639 relcnt++; 2640 //dbg_printf("%d-ElfObj_addrel(seg %d,offset x%x,type x%x,symidx %d,val %d)\n", 2641 //relcnt,seg, offset, type, symidx,val); 2642 2643 assert(seg >= 0 && seg < SegData.length); 2644 segdata = SegData[seg]; 2645 secidx = MAP_SEG2SECIDX(seg); 2646 assert(secidx != 0); 2647 2648 if (segdata.SDrel == null) 2649 { 2650 segdata.SDrel = cast(Outbuffer*) calloc(1, (Outbuffer).sizeof); 2651 assert(segdata.SDrel); 2652 } 2653 2654 if (segdata.SDrel.length() == 0) 2655 { IDXSEC relidx; 2656 2657 if (secidx == SHN_TEXT) 2658 relidx = SHN_RELTEXT; 2659 else if (secidx == SHN_DATA) 2660 relidx = SHN_RELDATA; 2661 else 2662 { 2663 // Get the section name, and make a copy because 2664 // elf_newsection() may reallocate the string buffer. 2665 char *section_name = cast(char *)GET_SECTION_NAME(secidx); 2666 size_t len = strlen(section_name) + 1; 2667 char[20] buf2 = void; 2668 char *p = len <= buf2.sizeof ? &buf2[0] : cast(char *)malloc(len); 2669 assert(p); 2670 memcpy(p, section_name, len); 2671 2672 relidx = elf_newsection(I64 ? ".rela" : ".rel", p, I64 ? SHT_RELA : SHT_REL, 0); 2673 if (p != &buf2[0]) 2674 free(p); 2675 segdata.SDrelidx = relidx; 2676 addSectionToComdat(relidx,seg); 2677 } 2678 2679 if (I64) 2680 { 2681 /* Note that we're using Elf32_Shdr here instead of Elf64_Shdr. This is to make 2682 * the code a bit simpler. In ElfObj_term(), we translate the Elf32_Shdr into the proper 2683 * Elf64_Shdr. 2684 */ 2685 Elf32_Shdr *relsec = &SecHdrTab[relidx]; 2686 relsec.sh_link = SHN_SYMTAB; 2687 relsec.sh_info = secidx; 2688 relsec.sh_entsize = Elf64_Rela.sizeof; 2689 relsec.sh_addralign = 8; 2690 } 2691 else 2692 { 2693 Elf32_Shdr *relsec = &SecHdrTab[relidx]; 2694 relsec.sh_link = SHN_SYMTAB; 2695 relsec.sh_info = secidx; 2696 relsec.sh_entsize = Elf32_Rel.sizeof; 2697 relsec.sh_addralign = 4; 2698 } 2699 } 2700 2701 if (I64) 2702 { 2703 Elf64_Rela rel; 2704 rel.r_offset = offset; // build relocation information 2705 rel.r_info = ELF64_R_INFO(symidx,type); 2706 rel.r_addend = val; 2707 buf = segdata.SDrel; 2708 buf.write(&rel,(rel).sizeof); 2709 segdata.SDrelcnt++; 2710 2711 if (offset >= segdata.SDrelmaxoff) 2712 segdata.SDrelmaxoff = offset; 2713 else 2714 { // insert numerically 2715 Elf64_Rela *relbuf = cast(Elf64_Rela *)buf.buf; 2716 int i = relbuf[segdata.SDrelindex].r_offset > offset ? 0 : segdata.SDrelindex; 2717 while (i < segdata.SDrelcnt) 2718 { 2719 if (relbuf[i].r_offset > offset) 2720 break; 2721 i++; 2722 } 2723 assert(i != segdata.SDrelcnt); // slide greater offsets down 2724 memmove(relbuf+i+1,relbuf+i,Elf64_Rela.sizeof * (segdata.SDrelcnt - i - 1)); 2725 *(relbuf+i) = rel; // copy to correct location 2726 segdata.SDrelindex = i; // next entry usually greater 2727 } 2728 } 2729 else 2730 { 2731 Elf32_Rel rel; 2732 rel.r_offset = cast(uint)offset; // build relocation information 2733 rel.r_info = ELF32_R_INFO(symidx,type); 2734 buf = segdata.SDrel; 2735 buf.write(&rel,rel.sizeof); 2736 segdata.SDrelcnt++; 2737 2738 if (offset >= segdata.SDrelmaxoff) 2739 segdata.SDrelmaxoff = offset; 2740 else 2741 { // insert numerically 2742 Elf32_Rel *relbuf = cast(Elf32_Rel *)buf.buf; 2743 int i = relbuf[segdata.SDrelindex].r_offset > offset ? 0 : segdata.SDrelindex; 2744 while (i < segdata.SDrelcnt) 2745 { 2746 if (relbuf[i].r_offset > offset) 2747 break; 2748 i++; 2749 } 2750 assert(i != segdata.SDrelcnt); // slide greater offsets down 2751 memmove(relbuf+i+1,relbuf+i,Elf32_Rel.sizeof * (segdata.SDrelcnt - i - 1)); 2752 *(relbuf+i) = rel; // copy to correct location 2753 segdata.SDrelindex = i; // next entry usually greater 2754 } 2755 } 2756 } 2757 2758 private size_t relsize64(uint type) 2759 { 2760 assert(I64); 2761 switch (type) 2762 { 2763 case R_X86_64_NONE: return 0; 2764 case R_X86_64_64: return 8; 2765 case R_X86_64_PC32: return 4; 2766 case R_X86_64_GOT32: return 4; 2767 case R_X86_64_PLT32: return 4; 2768 case R_X86_64_COPY: return 0; 2769 case R_X86_64_GLOB_DAT: return 8; 2770 case R_X86_64_JUMP_SLOT: return 8; 2771 case R_X86_64_RELATIVE: return 8; 2772 case R_X86_64_GOTPCREL: return 4; 2773 case R_X86_64_32: return 4; 2774 case R_X86_64_32S: return 4; 2775 case R_X86_64_16: return 2; 2776 case R_X86_64_PC16: return 2; 2777 case R_X86_64_8: return 1; 2778 case R_X86_64_PC8: return 1; 2779 case R_X86_64_DTPMOD64: return 8; 2780 case R_X86_64_DTPOFF64: return 8; 2781 case R_X86_64_TPOFF64: return 8; 2782 case R_X86_64_TLSGD: return 4; 2783 case R_X86_64_TLSLD: return 4; 2784 case R_X86_64_DTPOFF32: return 4; 2785 case R_X86_64_GOTTPOFF: return 4; 2786 case R_X86_64_TPOFF32: return 4; 2787 case R_X86_64_PC64: return 8; 2788 case R_X86_64_GOTOFF64: return 8; 2789 case R_X86_64_GOTPC32: return 4; 2790 2791 default: 2792 assert(0); 2793 } 2794 } 2795 2796 private size_t relsize32(uint type) 2797 { 2798 assert(I32); 2799 switch (type) 2800 { 2801 case R_386_NONE: return 0; 2802 case R_386_32: return 4; 2803 case R_386_PC32: return 4; 2804 case R_386_GOT32: return 4; 2805 case R_386_PLT32: return 4; 2806 case R_386_COPY: return 0; 2807 case R_386_GLOB_DAT: return 4; 2808 case R_386_JMP_SLOT: return 4; 2809 case R_386_RELATIVE: return 4; 2810 case R_386_GOTOFF: return 4; 2811 case R_386_GOTPC: return 4; 2812 case R_386_TLS_TPOFF: return 4; 2813 case R_386_TLS_IE: return 4; 2814 case R_386_TLS_GOTIE: return 4; 2815 case R_386_TLS_LE: return 4; 2816 case R_386_TLS_GD: return 4; 2817 case R_386_TLS_LDM: return 4; 2818 case R_386_TLS_GD_32: return 4; 2819 case R_386_TLS_GD_PUSH: return 4; 2820 case R_386_TLS_GD_CALL: return 4; 2821 case R_386_TLS_GD_POP: return 4; 2822 case R_386_TLS_LDM_32: return 4; 2823 case R_386_TLS_LDM_PUSH: return 4; 2824 case R_386_TLS_LDM_CALL: return 4; 2825 case R_386_TLS_LDM_POP: return 4; 2826 case R_386_TLS_LDO_32: return 4; 2827 case R_386_TLS_IE_32: return 4; 2828 case R_386_TLS_LE_32: return 4; 2829 case R_386_TLS_DTPMOD32: return 4; 2830 case R_386_TLS_DTPOFF32: return 4; 2831 case R_386_TLS_TPOFF32: return 4; 2832 2833 default: 2834 assert(0); 2835 } 2836 } 2837 2838 /******************************* 2839 * Write/Append a value to the given segment and offset. 2840 * targseg = the target segment for the relocation 2841 * offset = offset within target segment 2842 * val = addend or displacement from symbol 2843 * size = number of bytes to write 2844 */ 2845 private size_t writeaddrval(int targseg, size_t offset, targ_size_t val, size_t size) 2846 { 2847 assert(targseg >= 0 && targseg < SegData.length); 2848 2849 Outbuffer *buf = SegData[targseg].SDbuf; 2850 const save = buf.length(); 2851 buf.setsize(cast(uint)offset); 2852 buf.write(&val, cast(uint)size); 2853 // restore Outbuffer position 2854 if (save > offset + size) 2855 buf.setsize(cast(uint)save); 2856 return size; 2857 } 2858 2859 /******************************* 2860 * Write/Append a relocatable value to the given segment and offset. 2861 * Input: 2862 * targseg = the target segment for the relocation 2863 * offset = offset within target segment 2864 * reltype = ELF relocation type R_ARCH_XXXX 2865 * symidx = symbol base for relocation 2866 * val = addend or displacement from symbol 2867 */ 2868 size_t ElfObj_writerel(int targseg, size_t offset, reltype_t reltype, 2869 IDXSYM symidx, targ_size_t val) 2870 { 2871 assert(reltype != R_X86_64_NONE); 2872 2873 size_t sz; 2874 if (I64) 2875 { 2876 // Elf64_Rela stores addend in Rela.r_addend field 2877 sz = relsize64(reltype); 2878 writeaddrval(targseg, offset, 0, sz); 2879 ElfObj_addrel(targseg, offset, reltype, symidx, val); 2880 } 2881 else 2882 { 2883 assert(I32); 2884 // Elf32_Rel stores addend in target location 2885 sz = relsize32(reltype); 2886 writeaddrval(targseg, offset, val, sz); 2887 ElfObj_addrel(targseg, offset, reltype, symidx, 0); 2888 } 2889 return sz; 2890 } 2891 2892 /******************************* 2893 * Refer to address that is in the data segment. 2894 * Input: 2895 * seg = where the address is going 2896 * offset = offset within seg 2897 * val = displacement from address 2898 * targetdatum = DATA, CDATA or UDATA, depending where the address is 2899 * flags = CFoff, CFseg, CFoffset64, CFswitch 2900 * Example: 2901 * int *abc = &def[3]; 2902 * to allocate storage: 2903 * ElfObj_reftodatseg(DATA,offset,3 * (int *).sizeof,UDATA); 2904 * Note: 2905 * For I64 && (flags & CFoffset64) && (flags & CFswitch) 2906 * targetdatum is a symidx rather than a segment. 2907 */ 2908 2909 void ElfObj_reftodatseg(int seg,targ_size_t offset,targ_size_t val, 2910 uint targetdatum,int flags) 2911 { 2912 static if (0) 2913 { 2914 printf("ElfObj_reftodatseg(seg=%d, offset=x%llx, val=x%llx,data %x, flags %x)\n", 2915 seg,cast(ulong)offset,cast(ulong)val,targetdatum,flags); 2916 } 2917 2918 reltype_t relinfo; 2919 IDXSYM targetsymidx = STI_RODAT; 2920 if (I64) 2921 { 2922 2923 if (flags & CFoffset64) 2924 { 2925 relinfo = R_X86_64_64; 2926 if (flags & CFswitch) targetsymidx = targetdatum; 2927 } 2928 else if (flags & CFswitch) 2929 { 2930 relinfo = R_X86_64_PC32; 2931 targetsymidx = MAP_SEG2SYMIDX(targetdatum); 2932 } 2933 else if (MAP_SEG2TYP(seg) == CODE && config.flags3 & CFG3pic) 2934 { 2935 relinfo = R_X86_64_PC32; 2936 val -= 4; 2937 targetsymidx = MAP_SEG2SYMIDX(targetdatum); 2938 } 2939 else if (MAP_SEG2SEC(targetdatum).sh_flags & SHF_TLS) 2940 { 2941 if (config.flags3 & CFG3pie) 2942 relinfo = R_X86_64_TPOFF32; 2943 else 2944 relinfo = config.flags3 & CFG3pic ? R_X86_64_TLSGD : R_X86_64_TPOFF32; 2945 } 2946 else 2947 { 2948 relinfo = targetdatum == CDATA ? R_X86_64_32 : R_X86_64_32S; 2949 targetsymidx = MAP_SEG2SYMIDX(targetdatum); 2950 } 2951 } 2952 else 2953 { 2954 if (MAP_SEG2TYP(seg) == CODE && config.flags3 & CFG3pic) 2955 relinfo = R_386_GOTOFF; 2956 else if (MAP_SEG2SEC(targetdatum).sh_flags & SHF_TLS) 2957 { 2958 if (config.flags3 & CFG3pie) 2959 relinfo = R_386_TLS_LE; 2960 else 2961 relinfo = config.flags3 & CFG3pic ? R_386_TLS_GD : R_386_TLS_LE; 2962 } 2963 else 2964 relinfo = R_386_32; 2965 targetsymidx = MAP_SEG2SYMIDX(targetdatum); 2966 } 2967 ElfObj_writerel(seg, cast(uint)offset, relinfo, targetsymidx, val); 2968 } 2969 2970 /******************************* 2971 * Refer to address that is in the code segment. 2972 * Only offsets are output, regardless of the memory model. 2973 * Used to put values in switch address tables. 2974 * Input: 2975 * seg = where the address is going (CODE or DATA) 2976 * offset = offset within seg 2977 * val = displacement from start of this module 2978 */ 2979 2980 void ElfObj_reftocodeseg(int seg,targ_size_t offset,targ_size_t val) 2981 { 2982 //printf("ElfObj_reftocodeseg(seg=%d, offset=x%llx, val=x%llx, off=x%llx )\n",seg,offset,val, val - funcsym_p.Soffset); 2983 2984 reltype_t relinfo; 2985 static if (0) 2986 { 2987 if (MAP_SEG2TYP(seg) == CODE) 2988 { 2989 relinfo = RI_TYPE_PC32; 2990 ElfObj_writerel(seg, offset, relinfo, funcsym_p.Sxtrnnum, val - funcsym_p.Soffset); 2991 return; 2992 } 2993 } 2994 2995 if (I64) 2996 relinfo = (config.flags3 & CFG3pic) ? R_X86_64_PC32 : R_X86_64_32; 2997 else 2998 relinfo = (config.flags3 & CFG3pic) ? R_386_GOTOFF : R_386_32; 2999 ElfObj_writerel(seg, cast(uint)offset, relinfo, funcsym_p.Sxtrnnum, val - funcsym_p.Soffset); 3000 } 3001 3002 /******************************* 3003 * Refer to an identifier. 3004 * Input: 3005 * segtyp = where the address is going (CODE or DATA) 3006 * offset = offset within seg 3007 * s = Symbol table entry for identifier 3008 * val = displacement from identifier 3009 * flags = CFselfrel: self-relative 3010 * CFseg: get segment 3011 * CFoff: get offset 3012 * CFoffset64: 64 bit fixup 3013 * CFpc32: I64: PC relative 32 bit fixup 3014 * Returns: 3015 * number of bytes in reference (4 or 8) 3016 */ 3017 3018 int ElfObj_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val, 3019 int flags) 3020 { 3021 bool external = true; 3022 Outbuffer *buf; 3023 reltype_t relinfo = R_X86_64_NONE; 3024 int refseg; 3025 const segtyp = MAP_SEG2TYP(seg); 3026 //assert(val == 0); 3027 int retsize = (flags & CFoffset64) ? 8 : 4; 3028 3029 static if (0) 3030 { 3031 printf("\nElfObj_reftoident('%s' seg %d, offset x%llx, val x%llx, flags x%x)\n", 3032 s.Sident.ptr,seg,offset,val,flags); 3033 printf("Sseg = %d, Sxtrnnum = %d, retsize = %d\n",s.Sseg,s.Sxtrnnum,retsize); 3034 symbol_print(s); 3035 } 3036 3037 const tym_t ty = s.ty(); 3038 if (s.Sxtrnnum) 3039 { // identifier is defined somewhere else 3040 if (I64) 3041 { 3042 if (elfobj.SymbolTable64[s.Sxtrnnum].st_shndx != SHN_UNDEF) 3043 external = false; 3044 } 3045 else 3046 { 3047 if (elfobj.SymbolTable[s.Sxtrnnum].st_shndx != SHN_UNDEF) 3048 external = false; 3049 } 3050 } 3051 3052 switch (s.Sclass) 3053 { 3054 case SClocstat: 3055 if (I64) 3056 { 3057 if (s.Sfl == FLtlsdata) 3058 { 3059 if (config.flags3 & CFG3pie) 3060 relinfo = R_X86_64_TPOFF32; 3061 else 3062 relinfo = config.flags3 & CFG3pic ? R_X86_64_TLSGD : R_X86_64_TPOFF32; 3063 } 3064 else 3065 { relinfo = config.flags3 & CFG3pic ? R_X86_64_PC32 : R_X86_64_32; 3066 if (flags & CFpc32) 3067 relinfo = R_X86_64_PC32; 3068 } 3069 } 3070 else 3071 { 3072 if (s.Sfl == FLtlsdata) 3073 { 3074 if (config.flags3 & CFG3pie) 3075 relinfo = R_386_TLS_LE; 3076 else 3077 relinfo = config.flags3 & CFG3pic ? R_386_TLS_GD : R_386_TLS_LE; 3078 } 3079 else 3080 relinfo = config.flags3 & CFG3pic ? R_386_GOTOFF : R_386_32; 3081 } 3082 if (flags & CFoffset64 && relinfo == R_X86_64_32) 3083 { 3084 relinfo = R_X86_64_64; 3085 retsize = 8; 3086 } 3087 refseg = STI_RODAT; 3088 val += s.Soffset; 3089 goto outrel; 3090 3091 case SCcomdat: 3092 case_SCcomdat: 3093 case SCstatic: 3094 static if (0) 3095 { 3096 if ((s.Sflags & SFLthunk) && s.Soffset) 3097 { // A thunk symbol that has been defined 3098 assert(s.Sseg == seg); 3099 val = (s.Soffset+val) - (offset+4); 3100 goto outaddrval; 3101 } 3102 } 3103 goto case; 3104 3105 case SCextern: 3106 case SCcomdef: 3107 case_extern: 3108 case SCglobal: 3109 if (!s.Sxtrnnum) 3110 { // not in symbol table yet - class might change 3111 //printf("\tadding %s to fixlist\n",s.Sident.ptr); 3112 size_t numbyteswritten = addtofixlist(s,offset,seg,val,flags); 3113 assert(numbyteswritten == retsize); 3114 return retsize; 3115 } 3116 else 3117 { 3118 refseg = s.Sxtrnnum; // default to name symbol table entry 3119 3120 if (flags & CFselfrel) 3121 { // only for function references within code segments 3122 if (!external && // local definition found 3123 s.Sseg == seg && // within same code segment 3124 (!(config.flags3 & CFG3pic) || // not position indp code 3125 s.Sclass == SCstatic)) // or is pic, but declared static 3126 { // Can use PC relative 3127 //dbg_printf("\tdoing PC relative\n"); 3128 val = (s.Soffset+val) - (offset+4); 3129 } 3130 else 3131 { 3132 //dbg_printf("\tadding relocation\n"); 3133 if (s.Sclass == SCglobal && config.flags3 & CFG3pie && tyfunc(s.ty())) 3134 relinfo = I64 ? R_X86_64_PC32 : R_386_PC32; 3135 else if (I64) 3136 relinfo = config.flags3 & CFG3pic ? R_X86_64_PLT32 : R_X86_64_PC32; 3137 else 3138 relinfo = config.flags3 & CFG3pic ? R_386_PLT32 : R_386_PC32; 3139 val = -cast(targ_size_t)4; 3140 } 3141 } 3142 else 3143 { // code to code code to data, data to code, data to data refs 3144 if (s.Sclass == SCstatic) 3145 { // offset into .data or .bss seg 3146 refseg = MAP_SEG2SYMIDX(s.Sseg); 3147 // use segment symbol table entry 3148 val += s.Soffset; 3149 if (!(config.flags3 & CFG3pic) || // all static refs from normal code 3150 segtyp == DATA) // or refs from data from posi indp 3151 { 3152 if (I64) 3153 relinfo = (flags & CFpc32) ? R_X86_64_PC32 : R_X86_64_32; 3154 else 3155 relinfo = R_386_32; 3156 } 3157 else 3158 { 3159 relinfo = I64 ? R_X86_64_PC32 : R_386_GOTOFF; 3160 } 3161 } 3162 else if (config.flags3 & CFG3pic && s == GOTsym) 3163 { // relocation for Gbl Offset Tab 3164 relinfo = I64 ? R_X86_64_NONE : R_386_GOTPC; 3165 } 3166 else if (segtyp == DATA) 3167 { // relocation from within DATA seg 3168 relinfo = I64 ? R_X86_64_32 : R_386_32; 3169 if (I64 && flags & CFpc32) 3170 relinfo = R_X86_64_PC32; 3171 } 3172 else 3173 { // relocation from within CODE seg 3174 if (I64) 3175 { 3176 if (config.flags3 & CFG3pie && s.Sclass == SCglobal) 3177 relinfo = R_X86_64_PC32; 3178 else if (config.flags3 & CFG3pic) 3179 relinfo = R_X86_64_GOTPCREL; 3180 else 3181 relinfo = (flags & CFpc32) ? R_X86_64_PC32 : R_X86_64_32; 3182 } 3183 else 3184 { 3185 if (config.flags3 & CFG3pie && s.Sclass == SCglobal) 3186 relinfo = R_386_GOTOFF; 3187 else 3188 relinfo = config.flags3 & CFG3pic ? R_386_GOT32 : R_386_32; 3189 } 3190 } 3191 if ((s.ty() & mTYLINK) & mTYthread) 3192 { 3193 if (I64) 3194 { 3195 if (config.flags3 & CFG3pie) 3196 { 3197 if (s.Sclass == SCstatic || s.Sclass == SCglobal) 3198 relinfo = R_X86_64_TPOFF32; 3199 else 3200 relinfo = R_X86_64_GOTTPOFF; 3201 } 3202 else if (config.flags3 & CFG3pic) 3203 { 3204 /+if (s.Sclass == SCstatic || s.Sclass == SClocstat) 3205 // Could use 'local dynamic (LD)' to optimize multiple local TLS reads 3206 relinfo = R_X86_64_TLSGD; 3207 else+/ 3208 relinfo = R_X86_64_TLSGD; 3209 } 3210 else 3211 { 3212 if (s.Sclass == SCstatic || s.Sclass == SClocstat) 3213 relinfo = R_X86_64_TPOFF32; 3214 else 3215 relinfo = R_X86_64_GOTTPOFF; 3216 } 3217 } 3218 else 3219 { 3220 if (config.flags3 & CFG3pie) 3221 { 3222 if (s.Sclass == SCstatic || s.Sclass == SCglobal) 3223 relinfo = R_386_TLS_LE; 3224 else 3225 relinfo = R_386_TLS_GOTIE; 3226 } 3227 else if (config.flags3 & CFG3pic) 3228 { 3229 /+if (s.Sclass == SCstatic) 3230 // Could use 'local dynamic (LD)' to optimize multiple local TLS reads 3231 relinfo = R_386_TLS_GD; 3232 else+/ 3233 relinfo = R_386_TLS_GD; 3234 } 3235 else 3236 { 3237 if (s.Sclass == SCstatic) 3238 relinfo = R_386_TLS_LE; 3239 else 3240 relinfo = R_386_TLS_IE; 3241 } 3242 } 3243 } 3244 if (flags & CFoffset64 && relinfo == R_X86_64_32) 3245 { 3246 relinfo = R_X86_64_64; 3247 } 3248 } 3249 if (relinfo == R_X86_64_NONE) 3250 { 3251 outaddrval: 3252 writeaddrval(seg, cast(uint)offset, val, retsize); 3253 } 3254 else 3255 { 3256 outrel: 3257 //printf("\t\t************* adding relocation\n"); 3258 const size_t nbytes = ElfObj_writerel(seg, cast(uint)offset, relinfo, refseg, val); 3259 assert(nbytes == retsize); 3260 } 3261 } 3262 break; 3263 3264 case SCsinline: 3265 case SCeinline: 3266 printf ("Undefined inline value <<fixme>>\n"); 3267 //warerr(WM_undefined_inline,s.Sident.ptr); 3268 goto case; 3269 3270 case SCinline: 3271 if (tyfunc(ty)) 3272 { 3273 s.Sclass = SCextern; 3274 goto case_extern; 3275 } 3276 else if (config.flags2 & CFG2comdat) 3277 goto case_SCcomdat; // treat as initialized common block 3278 goto default; 3279 3280 default: 3281 //symbol_print(s); 3282 assert(0); 3283 } 3284 return retsize; 3285 } 3286 3287 /***************************************** 3288 * Generate far16 thunk. 3289 * Input: 3290 * s Symbol to generate a thunk for 3291 */ 3292 3293 void ElfObj_far16thunk(Symbol *s) 3294 { 3295 //dbg_printf("ElfObj_far16thunk('%s')\n", s.Sident.ptr); 3296 assert(0); 3297 } 3298 3299 /************************************** 3300 * Mark object file as using floating point. 3301 */ 3302 3303 void ElfObj_fltused() 3304 { 3305 //dbg_printf("ElfObj_fltused()\n"); 3306 } 3307 3308 /************************************ 3309 * Close and delete .OBJ file. 3310 */ 3311 3312 void elfobjfile_delete() 3313 { 3314 //remove(fobjname); // delete corrupt output file 3315 } 3316 3317 /********************************** 3318 * Terminate. 3319 */ 3320 3321 void elfobjfile_term() 3322 { 3323 static if (TERMCODE) 3324 { 3325 mem_free(fobjname); 3326 fobjname = null; 3327 } 3328 } 3329 3330 /********************************** 3331 * Write to the object file 3332 */ 3333 /+void objfile_write(FILE *fd, void *buffer, uint len) 3334 { 3335 fobjbuf.write(buffer, len); 3336 } 3337 +/ 3338 3339 private extern (D) 3340 int elf_align(targ_size_t size,int foffset) 3341 { 3342 if (size <= 1) 3343 return foffset; 3344 int offset = cast(int)((foffset + size - 1) & ~(size - 1)); 3345 if (offset > foffset) 3346 fobjbuf.writezeros(offset - foffset); 3347 return offset; 3348 } 3349 3350 /*************************************** 3351 * Stuff pointer to ModuleInfo into its own section (minfo). 3352 */ 3353 3354 version (MARS) 3355 { 3356 3357 void ElfObj_moduleinfo(Symbol *scc) 3358 { 3359 const CFflags = I64 ? (CFoffset64 | CFoff) : CFoff; 3360 3361 // needs to be writeable for PIC code, see Bugzilla 13117 3362 const shf_flags = SHF_ALLOC | SHF_WRITE; 3363 const seg = ElfObj_getsegment("minfo", null, SHT_PROGBITS, shf_flags, _tysize[TYnptr]); 3364 SegData[seg].SDoffset += 3365 ElfObj_reftoident(seg, SegData[seg].SDoffset, scc, 0, CFflags); 3366 } 3367 3368 /*************************************** 3369 * Create startup/shutdown code to register an executable/shared 3370 * library (DSO) with druntime. Create one for each object file and 3371 * put the sections into a COMDAT group. This will ensure that each 3372 * DSO gets registered only once. 3373 */ 3374 3375 private void obj_rtinit() 3376 { 3377 // section start/stop symbols are defined by the linker (http://www.airs.com/blog/archives/56) 3378 // make the symbols hidden so that each DSO gets its own brackets 3379 IDXSYM minfo_beg, minfo_end, dso_rec; 3380 3381 { 3382 // needs to be writeable for PIC code, see Bugzilla 13117 3383 const shf_flags = SHF_ALLOC | SHF_WRITE; 3384 3385 const namidx = ElfObj_addstr(symtab_strings,"__start_minfo"); 3386 minfo_beg = elf_addsym(namidx, 0, 0, STT_NOTYPE, STB_GLOBAL, SHN_UNDEF, STV_HIDDEN); 3387 3388 ElfObj_getsegment("minfo", null, SHT_PROGBITS, shf_flags, _tysize[TYnptr]); 3389 3390 const namidx2 = ElfObj_addstr(symtab_strings,"__stop_minfo"); 3391 minfo_end = elf_addsym(namidx2, 0, 0, STT_NOTYPE, STB_GLOBAL, SHN_UNDEF, STV_HIDDEN); 3392 } 3393 3394 // Create a COMDAT section group 3395 const groupseg = ElfObj_getsegment(".group.d_dso", null, SHT_GROUP, 0, 0); 3396 SegData[groupseg].SDbuf.write32(GRP_COMDAT); 3397 3398 { 3399 /* 3400 * Create an instance of DSORec as global static data in the section .data.d_dso_rec 3401 * It is writeable and allows the runtime to store information. 3402 * Make it a COMDAT so there's only one per DSO. 3403 * 3404 * typedef union 3405 * { 3406 * size_t id; 3407 * void *data; 3408 * } DSORec; 3409 */ 3410 const seg = ElfObj_getsegment(".data.d_dso_rec", null, SHT_PROGBITS, 3411 SHF_ALLOC|SHF_WRITE|SHF_GROUP, _tysize[TYnptr]); 3412 dso_rec = MAP_SEG2SYMIDX(seg); 3413 ElfObj_bytes(seg, 0, _tysize[TYnptr], null); 3414 // add to section group 3415 SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(seg)); 3416 3417 /* 3418 * Create an instance of DSO on the stack: 3419 * 3420 * typedef struct 3421 * { 3422 * size_t version; 3423 * DSORec *dso_rec; 3424 * void *minfo_beg, *minfo_end; 3425 * } DSO; 3426 * 3427 * Generate the following function as a COMDAT so there's only one per DSO: 3428 * .text.d_dso_init segment 3429 * push EBP 3430 * mov EBP,ESP 3431 * sub ESP,align 3432 * lea RAX,minfo_end[RIP] 3433 * push RAX 3434 * lea RAX,minfo_beg[RIP] 3435 * push RAX 3436 * lea RAX,.data.d_dso_rec[RIP] 3437 * push RAX 3438 * push 1 // version 3439 * mov RDI,RSP 3440 * call _d_dso_registry@PLT32 3441 * leave 3442 * ret 3443 * and then put a pointer to that function in .init_array and in .fini_array so it'll 3444 * get executed once upon loading and once upon unloading the DSO. 3445 */ 3446 const codseg = ElfObj_getsegment(".text.d_dso_init", null, SHT_PROGBITS, 3447 SHF_ALLOC|SHF_EXECINSTR|SHF_GROUP, _tysize[TYnptr]); 3448 // add to section group 3449 SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(codseg)); 3450 3451 debug 3452 { 3453 // adds a local symbol (name) to the code, useful to set a breakpoint 3454 const namidx = ElfObj_addstr(symtab_strings, "__d_dso_init"); 3455 elf_addsym(namidx, 0, 0, STT_FUNC, STB_LOCAL, MAP_SEG2SECIDX(codseg)); 3456 } 3457 3458 Outbuffer *buf = SegData[codseg].SDbuf; 3459 assert(!buf.length()); 3460 size_t off = 0; 3461 3462 // 16-byte align for call 3463 const size_t sizeof_dso = 6 * _tysize[TYnptr]; 3464 const size_t align_ = I64 ? 3465 // return address, RBP, DSO 3466 (-(2 * _tysize[TYnptr] + sizeof_dso) & 0xF) : 3467 // return address, EBP, EBX, DSO, arg 3468 (-(3 * _tysize[TYnptr] + sizeof_dso + _tysize[TYnptr]) & 0xF); 3469 3470 // push EBP 3471 buf.writeByte(0x50 + BP); 3472 off += 1; 3473 // mov EBP, ESP 3474 if (I64) 3475 { 3476 buf.writeByte(REX | REX_W); 3477 off += 1; 3478 } 3479 buf.writeByte(0x8B); 3480 buf.writeByte(modregrm(3,BP,SP)); 3481 off += 2; 3482 // sub ESP, align_ 3483 if (align_) 3484 { 3485 if (I64) 3486 { 3487 buf.writeByte(REX | REX_W); 3488 off += 1; 3489 } 3490 buf.writeByte(0x81); 3491 buf.writeByte(modregrm(3,5,SP)); 3492 buf.writeByte(align_ & 0xFF); 3493 buf.writeByte(align_ >> 8 & 0xFF); 3494 buf.writeByte(0); 3495 buf.writeByte(0); 3496 off += 6; 3497 } 3498 3499 if (config.flags3 & CFG3pic && I32) 3500 { // see cod3_load_got() for reference 3501 // push EBX 3502 buf.writeByte(0x50 + BX); 3503 off += 1; 3504 // call L1 3505 buf.writeByte(0xE8); 3506 buf.write32(0); 3507 // L1: pop EBX (now contains EIP) 3508 buf.writeByte(0x58 + BX); 3509 off += 6; 3510 // add EBX,_GLOBAL_OFFSET_TABLE_+3 3511 buf.writeByte(0x81); 3512 buf.writeByte(modregrm(3,0,BX)); 3513 off += 2; 3514 off += ElfObj_writerel(codseg, off, R_386_GOTPC, ElfObj_external(ElfObj_getGOTsym()), 3); 3515 } 3516 3517 reltype_t reltype; 3518 opcode_t op; 3519 if (0 && config.flags3 & CFG3pie) 3520 { 3521 op = LOD; 3522 reltype = I64 ? R_X86_64_GOTPCREL : R_386_GOT32; 3523 } 3524 else if (config.flags3 & CFG3pic) 3525 { 3526 op = LEA; 3527 reltype = I64 ? R_X86_64_PC32 : R_386_GOTOFF; 3528 } 3529 else 3530 { 3531 op = LEA; 3532 reltype = I64 ? R_X86_64_32 : R_386_32; 3533 } 3534 3535 const IDXSYM[3] syms = [dso_rec, minfo_beg, minfo_end]; 3536 3537 for (size_t i = (syms).sizeof / (syms[0]).sizeof; i--; ) 3538 { 3539 const IDXSYM sym = syms[i]; 3540 3541 if (config.flags3 & CFG3pic) 3542 { 3543 if (I64) 3544 { 3545 // lea RAX, sym[RIP] 3546 buf.writeByte(REX | REX_W); 3547 buf.writeByte(op); 3548 buf.writeByte(modregrm(0,AX,5)); 3549 off += 3; 3550 off += ElfObj_writerel(codseg, off, reltype, syms[i], -4); 3551 } 3552 else 3553 { 3554 // lea EAX, sym[EBX] 3555 buf.writeByte(op); 3556 buf.writeByte(modregrm(2,AX,BX)); 3557 off += 2; 3558 off += ElfObj_writerel(codseg, off, reltype, syms[i], 0); 3559 } 3560 } 3561 else 3562 { 3563 // mov EAX, sym 3564 buf.writeByte(0xB8 + AX); 3565 off += 1; 3566 off += ElfObj_writerel(codseg, off, reltype, syms[i], 0); 3567 } 3568 // push RAX 3569 buf.writeByte(0x50 + AX); 3570 off += 1; 3571 } 3572 buf.writeByte(0x6A); // PUSH 1 3573 buf.writeByte(1); // version flag to simplify future extensions 3574 off += 2; 3575 3576 if (I64) 3577 { // mov RDI, DSO* 3578 buf.writeByte(REX | REX_W); 3579 buf.writeByte(0x8B); 3580 buf.writeByte(modregrm(3,DI,SP)); 3581 off += 3; 3582 } 3583 else 3584 { // push DSO* 3585 buf.writeByte(0x50 + SP); 3586 off += 1; 3587 } 3588 3589 static if (REQUIRE_DSO_REGISTRY) 3590 { 3591 3592 const IDXSYM symidx = ElfObj_external_def("_d_dso_registry"); 3593 3594 // call _d_dso_registry@PLT 3595 buf.writeByte(0xE8); 3596 off += 1; 3597 off += ElfObj_writerel(codseg, off, I64 ? R_X86_64_PLT32 : R_386_PLT32, symidx, -4); 3598 3599 } 3600 else 3601 { 3602 3603 // use a weak reference for _d_dso_registry 3604 const namidx2 = ElfObj_addstr(symtab_strings, "_d_dso_registry"); 3605 const IDXSYM symidx = elf_addsym(namidx2, 0, 0, STT_NOTYPE, STB_WEAK, SHN_UNDEF); 3606 3607 if (config.flags3 & CFG3pic) 3608 { 3609 if (I64) 3610 { 3611 // cmp foo@GOT[RIP], 0 3612 buf.writeByte(REX | REX_W); 3613 buf.writeByte(0x83); 3614 buf.writeByte(modregrm(0,7,5)); 3615 off += 3; 3616 const reltype2 = /*config.flags3 & CFG3pie ? R_X86_64_PC32 :*/ R_X86_64_GOTPCREL; 3617 off += ElfObj_writerel(codseg, off, reltype2, symidx, -5); 3618 buf.writeByte(0); 3619 off += 1; 3620 } 3621 else 3622 { 3623 // cmp foo[GOT], 0 3624 buf.writeByte(0x81); 3625 buf.writeByte(modregrm(2,7,BX)); 3626 off += 2; 3627 const reltype2 = /*config.flags3 & CFG3pie ? R_386_GOTOFF :*/ R_386_GOT32; 3628 off += ElfObj_writerel(codseg, off, reltype2, symidx, 0); 3629 buf.write32(0); 3630 off += 4; 3631 } 3632 // jz +5 3633 buf.writeByte(0x74); 3634 buf.writeByte(0x05); 3635 off += 2; 3636 3637 // call foo@PLT[RIP] 3638 buf.writeByte(0xE8); 3639 off += 1; 3640 off += ElfObj_writerel(codseg, off, I64 ? R_X86_64_PLT32 : R_386_PLT32, symidx, -4); 3641 } 3642 else 3643 { 3644 // mov ECX, offset foo 3645 buf.writeByte(0xB8 + CX); 3646 off += 1; 3647 const reltype2 = I64 ? R_X86_64_32 : R_386_32; 3648 off += ElfObj_writerel(codseg, off, reltype2, symidx, 0); 3649 3650 // test ECX, ECX 3651 buf.writeByte(0x85); 3652 buf.writeByte(modregrm(3,CX,CX)); 3653 3654 // jz +5 (skip call) 3655 buf.writeByte(0x74); 3656 buf.writeByte(0x05); 3657 off += 4; 3658 3659 // call _d_dso_registry[RIP] 3660 buf.writeByte(0xE8); 3661 off += 1; 3662 off += ElfObj_writerel(codseg, off, I64 ? R_X86_64_PC32 : R_386_PC32, symidx, -4); 3663 } 3664 3665 } 3666 3667 if (config.flags3 & CFG3pic && I32) 3668 { // mov EBX,[EBP-4-align_] 3669 buf.writeByte(0x8B); 3670 buf.writeByte(modregrm(1,BX,BP)); 3671 buf.writeByte(cast(int)(-4-align_)); 3672 off += 3; 3673 } 3674 // leave 3675 buf.writeByte(0xC9); 3676 // ret 3677 buf.writeByte(0xC3); 3678 off += 2; 3679 Offset(codseg) = off; 3680 3681 // put a reference into .init_array/.fini_array each 3682 // needs to be writeable for PIC code, see Bugzilla 13117 3683 const int flags = SHF_ALLOC | SHF_WRITE | SHF_GROUP; 3684 { 3685 enum fini_name = USE_INIT_ARRAY ? ".fini_array.d_dso_dtor" : ".dtors.d_dso_dtor"; 3686 enum fini_type = USE_INIT_ARRAY ? SHT_FINI_ARRAY : SHT_PROGBITS; 3687 const cdseg = ElfObj_getsegment(fini_name.ptr, null, fini_type, flags, _tysize[TYnptr]); 3688 assert(!SegData[cdseg].SDbuf.length()); 3689 // add to section group 3690 SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(cdseg)); 3691 // relocation 3692 const reltype2 = I64 ? R_X86_64_64 : R_386_32; 3693 SegData[cdseg].SDoffset += ElfObj_writerel(cdseg, 0, reltype2, MAP_SEG2SYMIDX(codseg), 0); 3694 } 3695 { 3696 enum init_name = USE_INIT_ARRAY ? ".init_array.d_dso_ctor" : ".ctors.d_dso_ctor"; 3697 enum init_type = USE_INIT_ARRAY ? SHT_INIT_ARRAY : SHT_PROGBITS; 3698 const cdseg = ElfObj_getsegment(init_name.ptr, null, init_type, flags, _tysize[TYnptr]); 3699 assert(!SegData[cdseg].SDbuf.length()); 3700 // add to section group 3701 SegData[groupseg].SDbuf.write32(MAP_SEG2SECIDX(cdseg)); 3702 // relocation 3703 const reltype2 = I64 ? R_X86_64_64 : R_386_32; 3704 SegData[cdseg].SDoffset += ElfObj_writerel(cdseg, 0, reltype2, MAP_SEG2SYMIDX(codseg), 0); 3705 } 3706 } 3707 // set group section infos 3708 Offset(groupseg) = SegData[groupseg].SDbuf.length(); 3709 Elf32_Shdr *p = MAP_SEG2SEC(groupseg); 3710 p.sh_link = SHN_SYMTAB; 3711 p.sh_info = dso_rec; // set the dso_rec as group symbol 3712 p.sh_entsize = IDXSYM.sizeof; 3713 p.sh_size = cast(uint)Offset(groupseg); 3714 } 3715 3716 } 3717 3718 /************************************* 3719 */ 3720 3721 void ElfObj_gotref(Symbol *s) 3722 { 3723 //printf("ElfObj_gotref(%x '%s', %d)\n",s,s.Sident.ptr, s.Sclass); 3724 switch(s.Sclass) 3725 { 3726 case SCstatic: 3727 case SClocstat: 3728 s.Sfl = FLgotoff; 3729 break; 3730 3731 case SCextern: 3732 case SCglobal: 3733 case SCcomdat: 3734 case SCcomdef: 3735 s.Sfl = FLgot; 3736 break; 3737 3738 default: 3739 break; 3740 } 3741 } 3742 3743 Symbol *ElfObj_tlv_bootstrap() 3744 { 3745 // specific for Mach-O 3746 assert(0); 3747 } 3748 3749 void ElfObj_write_pointerRef(Symbol* s, uint off) 3750 { 3751 } 3752 3753 /****************************************** 3754 * Generate fixup specific to .eh_frame and .gcc_except_table sections. 3755 * Params: 3756 * seg = segment of where to write fixup 3757 * offset = offset of where to write fixup 3758 * s = fixup is a reference to this Symbol 3759 * val = displacement from s 3760 * Returns: 3761 * number of bytes written at seg:offset 3762 */ 3763 int elf_dwarf_reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val) 3764 { 3765 if (config.flags3 & CFG3pic) 3766 { 3767 /* fixup: R_X86_64_PC32 sym="DW.ref.name" 3768 * symtab: .weak DW.ref.name,@OBJECT,VALUE=.data.DW.ref.name+0x00,SIZE=8 3769 * Section 13 .data.DW.ref.name PROGBITS,ALLOC,WRITE,SIZE=0x0008(8),OFFSET=0x0138,ALIGN=8 3770 * 0138: 0 0 0 0 0 0 0 0 ........ 3771 * Section 14 .rela.data.DW.ref.name RELA,ENTRIES=1,OFFSET=0x0E18,ALIGN=8,LINK=22,INFO=13 3772 * 0 offset=00000000 addend=0000000000000000 type=R_X86_64_64 sym="name" 3773 */ 3774 if (!s.Sdw_ref_idx) 3775 { 3776 const dataDWref_seg = ElfObj_getsegment(".data.DW.ref.", s.Sident.ptr, SHT_PROGBITS, SHF_ALLOC|SHF_WRITE, I64 ? 8 : 4); 3777 Outbuffer *buf = SegData[dataDWref_seg].SDbuf; 3778 assert(buf.length() == 0); 3779 ElfObj_reftoident(dataDWref_seg, 0, s, 0, I64 ? CFoffset64 : CFoff); 3780 3781 // Add "DW.ref." ~ name to the symtab_strings table 3782 const namidx = cast(IDXSTR)symtab_strings.length(); 3783 symtab_strings.writeString("DW.ref."); 3784 symtab_strings.setsize(cast(uint)(symtab_strings.length() - 1)); // back up over terminating 0 3785 symtab_strings.writeString(s.Sident.ptr); 3786 3787 s.Sdw_ref_idx = elf_addsym(namidx, val, 8, STT_OBJECT, STB_WEAK, MAP_SEG2SECIDX(dataDWref_seg), STV_HIDDEN); 3788 } 3789 ElfObj_writerel(seg, cast(uint)offset, I64 ? R_X86_64_PC32 : R_386_PC32, s.Sdw_ref_idx, 0); 3790 } 3791 else 3792 { 3793 ElfObj_reftoident(seg, offset, s, val, CFoff); 3794 //dwarf_addrel(seg, offset, s.Sseg, s.Soffset); 3795 //et.write32(s.Soffset); 3796 } 3797 return 4; 3798 } 3799 3800 } 3801 3802 }