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