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