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