github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/link/internal/ld/xcoff.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ld 6 7 import ( 8 "bytes" 9 "github.com/gagliardetto/golang-go/cmd/internal/objabi" 10 "github.com/gagliardetto/golang-go/cmd/link/internal/sym" 11 "encoding/binary" 12 "io/ioutil" 13 "math/bits" 14 "path/filepath" 15 "sort" 16 "strings" 17 ) 18 19 // This file handles all algorithms related to XCOFF files generation. 20 // Most of them are adaptations of the ones in cmd/link/internal/pe.go 21 // as PE and XCOFF are based on COFF files. 22 // XCOFF files generated are 64 bits. 23 24 const ( 25 // Total amount of space to reserve at the start of the file 26 // for File Header, Auxiliary Header, and Section Headers. 27 // May waste some. 28 XCOFFHDRRESERVE = FILHSZ_64 + AOUTHSZ_EXEC64 + SCNHSZ_64*23 29 XCOFFSECTALIGN int64 = 32 // base on dump -o 30 31 // XCOFF binaries should normally have all its sections position-independent. 32 // However, this is not yet possible for .text because of some R_ADDR relocations 33 // inside RODATA symbols. 34 // .data and .bss are position-independent so their address start inside a unreachable 35 // segment during execution to force segfault if something is wrong. 36 XCOFFTEXTBASE = 0x100000000 // Start of text address 37 XCOFFDATABASE = 0x200000000 // Start of data address 38 ) 39 40 // File Header 41 type XcoffFileHdr64 struct { 42 Fmagic uint16 // Target machine 43 Fnscns uint16 // Number of sections 44 Ftimedat int32 // Time and date of file creation 45 Fsymptr uint64 // Byte offset to symbol table start 46 Fopthdr uint16 // Number of bytes in optional header 47 Fflags uint16 // Flags 48 Fnsyms int32 // Number of entries in symbol table 49 } 50 51 const ( 52 U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF 53 ) 54 55 // Flags that describe the type of the object file. 56 const ( 57 F_RELFLG = 0x0001 58 F_EXEC = 0x0002 59 F_LNNO = 0x0004 60 F_FDPR_PROF = 0x0010 61 F_FDPR_OPTI = 0x0020 62 F_DSA = 0x0040 63 F_VARPG = 0x0100 64 F_DYNLOAD = 0x1000 65 F_SHROBJ = 0x2000 66 F_LOADONLY = 0x4000 67 ) 68 69 // Auxiliary Header 70 type XcoffAoutHdr64 struct { 71 Omagic int16 // Flags - Ignored If Vstamp Is 1 72 Ovstamp int16 // Version 73 Odebugger uint32 // Reserved For Debugger 74 Otextstart uint64 // Virtual Address Of Text 75 Odatastart uint64 // Virtual Address Of Data 76 Otoc uint64 // Toc Address 77 Osnentry int16 // Section Number For Entry Point 78 Osntext int16 // Section Number For Text 79 Osndata int16 // Section Number For Data 80 Osntoc int16 // Section Number For Toc 81 Osnloader int16 // Section Number For Loader 82 Osnbss int16 // Section Number For Bss 83 Oalgntext int16 // Max Text Alignment 84 Oalgndata int16 // Max Data Alignment 85 Omodtype [2]byte // Module Type Field 86 Ocpuflag uint8 // Bit Flags - Cputypes Of Objects 87 Ocputype uint8 // Reserved for CPU type 88 Otextpsize uint8 // Requested text page size 89 Odatapsize uint8 // Requested data page size 90 Ostackpsize uint8 // Requested stack page size 91 Oflags uint8 // Flags And TLS Alignment 92 Otsize uint64 // Text Size In Bytes 93 Odsize uint64 // Data Size In Bytes 94 Obsize uint64 // Bss Size In Bytes 95 Oentry uint64 // Entry Point Address 96 Omaxstack uint64 // Max Stack Size Allowed 97 Omaxdata uint64 // Max Data Size Allowed 98 Osntdata int16 // Section Number For Tdata Section 99 Osntbss int16 // Section Number For Tbss Section 100 Ox64flags uint16 // Additional Flags For 64-Bit Objects 101 Oresv3a int16 // Reserved 102 Oresv3 [2]int32 // Reserved 103 } 104 105 // Section Header 106 type XcoffScnHdr64 struct { 107 Sname [8]byte // Section Name 108 Spaddr uint64 // Physical Address 109 Svaddr uint64 // Virtual Address 110 Ssize uint64 // Section Size 111 Sscnptr uint64 // File Offset To Raw Data 112 Srelptr uint64 // File Offset To Relocation 113 Slnnoptr uint64 // File Offset To Line Numbers 114 Snreloc uint32 // Number Of Relocation Entries 115 Snlnno uint32 // Number Of Line Number Entries 116 Sflags uint32 // flags 117 } 118 119 // Flags defining the section type. 120 const ( 121 STYP_DWARF = 0x0010 122 STYP_TEXT = 0x0020 123 STYP_DATA = 0x0040 124 STYP_BSS = 0x0080 125 STYP_EXCEPT = 0x0100 126 STYP_INFO = 0x0200 127 STYP_TDATA = 0x0400 128 STYP_TBSS = 0x0800 129 STYP_LOADER = 0x1000 130 STYP_DEBUG = 0x2000 131 STYP_TYPCHK = 0x4000 132 STYP_OVRFLO = 0x8000 133 ) 134 const ( 135 SSUBTYP_DWINFO = 0x10000 // DWARF info section 136 SSUBTYP_DWLINE = 0x20000 // DWARF line-number section 137 SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section 138 SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section 139 SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section 140 SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section 141 SSUBTYP_DWSTR = 0x70000 // DWARF strings section 142 SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section 143 SSUBTYP_DWLOC = 0x90000 // DWARF location lists section 144 SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section 145 SSUBTYP_DWMAC = 0xB0000 // DWARF macros section 146 ) 147 148 // Headers size 149 const ( 150 FILHSZ_32 = 20 151 FILHSZ_64 = 24 152 AOUTHSZ_EXEC32 = 72 153 AOUTHSZ_EXEC64 = 120 154 SCNHSZ_32 = 40 155 SCNHSZ_64 = 72 156 LDHDRSZ_32 = 32 157 LDHDRSZ_64 = 56 158 LDSYMSZ_64 = 24 159 RELSZ_64 = 14 160 ) 161 162 // Type representing all XCOFF symbols. 163 type xcoffSym interface { 164 } 165 166 // Symbol Table Entry 167 type XcoffSymEnt64 struct { 168 Nvalue uint64 // Symbol value 169 Noffset uint32 // Offset of the name in string table or .debug section 170 Nscnum int16 // Section number of symbol 171 Ntype uint16 // Basic and derived type specification 172 Nsclass uint8 // Storage class of symbol 173 Nnumaux int8 // Number of auxiliary entries 174 } 175 176 const SYMESZ = 18 177 178 const ( 179 // Nscnum 180 N_DEBUG = -2 181 N_ABS = -1 182 N_UNDEF = 0 183 184 //Ntype 185 SYM_V_INTERNAL = 0x1000 186 SYM_V_HIDDEN = 0x2000 187 SYM_V_PROTECTED = 0x3000 188 SYM_V_EXPORTED = 0x4000 189 SYM_TYPE_FUNC = 0x0020 // is function 190 ) 191 192 // Storage Class. 193 const ( 194 C_NULL = 0 // Symbol table entry marked for deletion 195 C_EXT = 2 // External symbol 196 C_STAT = 3 // Static symbol 197 C_BLOCK = 100 // Beginning or end of inner block 198 C_FCN = 101 // Beginning or end of function 199 C_FILE = 103 // Source file name and compiler information 200 C_HIDEXT = 107 // Unnamed external symbol 201 C_BINCL = 108 // Beginning of include file 202 C_EINCL = 109 // End of include file 203 C_WEAKEXT = 111 // Weak external symbol 204 C_DWARF = 112 // DWARF symbol 205 C_GSYM = 128 // Global variable 206 C_LSYM = 129 // Automatic variable allocated on stack 207 C_PSYM = 130 // Argument to subroutine allocated on stack 208 C_RSYM = 131 // Register variable 209 C_RPSYM = 132 // Argument to function or procedure stored in register 210 C_STSYM = 133 // Statically allocated symbol 211 C_BCOMM = 135 // Beginning of common block 212 C_ECOML = 136 // Local member of common block 213 C_ECOMM = 137 // End of common block 214 C_DECL = 140 // Declaration of object 215 C_ENTRY = 141 // Alternate entry 216 C_FUN = 142 // Function or procedure 217 C_BSTAT = 143 // Beginning of static block 218 C_ESTAT = 144 // End of static block 219 C_GTLS = 145 // Global thread-local variable 220 C_STTLS = 146 // Static thread-local variable 221 ) 222 223 // File Auxiliary Entry 224 type XcoffAuxFile64 struct { 225 Xzeroes uint32 // The name is always in the string table 226 Xoffset uint32 // Offset in the string table 227 X_pad1 [6]byte 228 Xftype uint8 // Source file string type 229 X_pad2 [2]byte 230 Xauxtype uint8 // Type of auxiliary entry 231 } 232 233 // Function Auxiliary Entry 234 type XcoffAuxFcn64 struct { 235 Xlnnoptr uint64 // File pointer to line number 236 Xfsize uint32 // Size of function in bytes 237 Xendndx uint32 // Symbol table index of next entry 238 Xpad uint8 // Unused 239 Xauxtype uint8 // Type of auxiliary entry 240 } 241 242 // csect Auxiliary Entry. 243 type XcoffAuxCSect64 struct { 244 Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index 245 Xparmhash uint32 // Offset of parameter type-check string 246 Xsnhash uint16 // .typchk section number 247 Xsmtyp uint8 // Symbol alignment and type 248 Xsmclas uint8 // Storage-mapping class 249 Xscnlenhi uint32 // Upper 4 bytes of length or symbol table index 250 Xpad uint8 // Unused 251 Xauxtype uint8 // Type of auxiliary entry 252 } 253 254 // DWARF Auxiliary Entry 255 type XcoffAuxDWARF64 struct { 256 Xscnlen uint64 // Length of this symbol section 257 X_pad [9]byte 258 Xauxtype uint8 // Type of auxiliary entry 259 } 260 261 // Auxiliary type 262 const ( 263 _AUX_EXCEPT = 255 264 _AUX_FCN = 254 265 _AUX_SYM = 253 266 _AUX_FILE = 252 267 _AUX_CSECT = 251 268 _AUX_SECT = 250 269 ) 270 271 // Xftype field 272 const ( 273 XFT_FN = 0 // Source File Name 274 XFT_CT = 1 // Compile Time Stamp 275 XFT_CV = 2 // Compiler Version Number 276 XFT_CD = 128 // Compiler Defined Information/ 277 278 ) 279 280 // Symbol type field. 281 const ( 282 XTY_ER = 0 // External reference 283 XTY_SD = 1 // Section definition 284 XTY_LD = 2 // Label definition 285 XTY_CM = 3 // Common csect definition 286 XTY_WK = 0x8 // Weak symbol 287 XTY_EXP = 0x10 // Exported symbol 288 XTY_ENT = 0x20 // Entry point symbol 289 XTY_IMP = 0x40 // Imported symbol 290 ) 291 292 // Storage-mapping class. 293 const ( 294 XMC_PR = 0 // Program code 295 XMC_RO = 1 // Read-only constant 296 XMC_DB = 2 // Debug dictionary table 297 XMC_TC = 3 // TOC entry 298 XMC_UA = 4 // Unclassified 299 XMC_RW = 5 // Read/Write data 300 XMC_GL = 6 // Global linkage 301 XMC_XO = 7 // Extended operation 302 XMC_SV = 8 // 32-bit supervisor call descriptor 303 XMC_BS = 9 // BSS class 304 XMC_DS = 10 // Function descriptor 305 XMC_UC = 11 // Unnamed FORTRAN common 306 XMC_TC0 = 15 // TOC anchor 307 XMC_TD = 16 // Scalar data entry in the TOC 308 XMC_SV64 = 17 // 64-bit supervisor call descriptor 309 XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit 310 XMC_TL = 20 // Read/Write thread-local data 311 XMC_UL = 21 // Read/Write thread-local data (.tbss) 312 XMC_TE = 22 // TOC entry 313 ) 314 315 // Loader Header 316 type XcoffLdHdr64 struct { 317 Lversion int32 // Loader section version number 318 Lnsyms int32 // Number of symbol table entries 319 Lnreloc int32 // Number of relocation table entries 320 Listlen uint32 // Length of import file ID string table 321 Lnimpid int32 // Number of import file IDs 322 Lstlen uint32 // Length of string table 323 Limpoff uint64 // Offset to start of import file IDs 324 Lstoff uint64 // Offset to start of string table 325 Lsymoff uint64 // Offset to start of symbol table 326 Lrldoff uint64 // Offset to start of relocation entries 327 } 328 329 // Loader Symbol 330 type XcoffLdSym64 struct { 331 Lvalue uint64 // Address field 332 Loffset uint32 // Byte offset into string table of symbol name 333 Lscnum int16 // Section number containing symbol 334 Lsmtype int8 // Symbol type, export, import flags 335 Lsmclas int8 // Symbol storage class 336 Lifile int32 // Import file ID; ordinal of import file IDs 337 Lparm uint32 // Parameter type-check field 338 } 339 340 type xcoffLoaderSymbol struct { 341 sym *sym.Symbol 342 smtype int8 343 smclas int8 344 } 345 346 type XcoffLdImportFile64 struct { 347 Limpidpath string 348 Limpidbase string 349 Limpidmem string 350 } 351 352 type XcoffLdRel64 struct { 353 Lvaddr uint64 // Address Field 354 Lrtype uint16 // Relocation Size and Type 355 Lrsecnm int16 // Section Number being relocated 356 Lsymndx int32 // Loader-Section symbol table index 357 } 358 359 // xcoffLoaderReloc holds information about a relocation made by the loader. 360 type xcoffLoaderReloc struct { 361 sym *sym.Symbol 362 rel *sym.Reloc 363 rtype uint16 364 symndx int32 365 } 366 367 const ( 368 XCOFF_R_POS = 0x00 // A(sym) Positive Relocation 369 XCOFF_R_NEG = 0x01 // -A(sym) Negative Relocation 370 XCOFF_R_REL = 0x02 // A(sym-*) Relative to self 371 XCOFF_R_TOC = 0x03 // A(sym-TOC) Relative to TOC 372 XCOFF_R_TRL = 0x12 // A(sym-TOC) TOC Relative indirect load. 373 374 XCOFF_R_TRLA = 0x13 // A(sym-TOC) TOC Rel load address. modifiable inst 375 XCOFF_R_GL = 0x05 // A(external TOC of sym) Global Linkage 376 XCOFF_R_TCL = 0x06 // A(local TOC of sym) Local object TOC address 377 XCOFF_R_RL = 0x0C // A(sym) Pos indirect load. modifiable instruction 378 XCOFF_R_RLA = 0x0D // A(sym) Pos Load Address. modifiable instruction 379 XCOFF_R_REF = 0x0F // AL0(sym) Non relocating ref. No garbage collect 380 XCOFF_R_BA = 0x08 // A(sym) Branch absolute. Cannot modify instruction 381 XCOFF_R_RBA = 0x18 // A(sym) Branch absolute. modifiable instruction 382 XCOFF_R_BR = 0x0A // A(sym-*) Branch rel to self. non modifiable 383 XCOFF_R_RBR = 0x1A // A(sym-*) Branch rel to self. modifiable instr 384 385 XCOFF_R_TLS = 0x20 // General-dynamic reference to TLS symbol 386 XCOFF_R_TLS_IE = 0x21 // Initial-exec reference to TLS symbol 387 XCOFF_R_TLS_LD = 0x22 // Local-dynamic reference to TLS symbol 388 XCOFF_R_TLS_LE = 0x23 // Local-exec reference to TLS symbol 389 XCOFF_R_TLSM = 0x24 // Module reference to TLS symbol 390 XCOFF_R_TLSML = 0x25 // Module reference to local (own) module 391 392 XCOFF_R_TOCU = 0x30 // Relative to TOC - high order bits 393 XCOFF_R_TOCL = 0x31 // Relative to TOC - low order bits 394 ) 395 396 type XcoffLdStr64 struct { 397 size uint16 398 name string 399 } 400 401 // xcoffFile is used to build XCOFF file. 402 type xcoffFile struct { 403 xfhdr XcoffFileHdr64 404 xahdr XcoffAoutHdr64 405 sections []*XcoffScnHdr64 406 sectText *XcoffScnHdr64 407 sectData *XcoffScnHdr64 408 sectBss *XcoffScnHdr64 409 stringTable xcoffStringTable 410 sectNameToScnum map[string]int16 411 loaderSize uint64 412 symtabOffset int64 // offset to the start of symbol table 413 symbolCount uint32 // number of symbol table records written 414 symtabSym []xcoffSym // XCOFF symbols for the symbol table 415 dynLibraries map[string]int // Dynamic libraries in .loader section. The integer represents its import file number (- 1) 416 loaderSymbols []*xcoffLoaderSymbol // symbols inside .loader symbol table 417 loaderReloc []*xcoffLoaderReloc // Reloc that must be made inside loader 418 } 419 420 // Var used by XCOFF Generation algorithms 421 var ( 422 xfile xcoffFile 423 ) 424 425 // xcoffStringTable is a XCOFF string table. 426 type xcoffStringTable struct { 427 strings []string 428 stringsLen int 429 } 430 431 // size returns size of string table t. 432 func (t *xcoffStringTable) size() int { 433 // string table starts with 4-byte length at the beginning 434 return t.stringsLen + 4 435 } 436 437 // add adds string str to string table t. 438 func (t *xcoffStringTable) add(str string) int { 439 off := t.size() 440 t.strings = append(t.strings, str) 441 t.stringsLen += len(str) + 1 // each string will have 0 appended to it 442 return off 443 } 444 445 // write writes string table t into the output file. 446 func (t *xcoffStringTable) write(out *OutBuf) { 447 out.Write32(uint32(t.size())) 448 for _, s := range t.strings { 449 out.WriteString(s) 450 out.Write8(0) 451 } 452 } 453 454 // write writes XCOFF section sect into the output file. 455 func (sect *XcoffScnHdr64) write(ctxt *Link) { 456 binary.Write(ctxt.Out, binary.BigEndian, sect) 457 ctxt.Out.Write32(0) // Add 4 empty bytes at the end to match alignment 458 } 459 460 // addSection adds section to the XCOFF file f. 461 func (f *xcoffFile) addSection(name string, addr uint64, size uint64, fileoff uint64, flags uint32) *XcoffScnHdr64 { 462 sect := &XcoffScnHdr64{ 463 Spaddr: addr, 464 Svaddr: addr, 465 Ssize: size, 466 Sscnptr: fileoff, 467 Sflags: flags, 468 } 469 copy(sect.Sname[:], name) // copy string to [8]byte 470 f.sections = append(f.sections, sect) 471 f.sectNameToScnum[name] = int16(len(f.sections)) 472 return sect 473 } 474 475 // addDwarfSection adds a dwarf section to the XCOFF file f. 476 // This function is similar to addSection, but Dwarf section names 477 // must be modified to conventional names and they are various subtypes. 478 func (f *xcoffFile) addDwarfSection(s *sym.Section) *XcoffScnHdr64 { 479 newName, subtype := xcoffGetDwarfSubtype(s.Name) 480 return f.addSection(newName, 0, s.Length, s.Seg.Fileoff+s.Vaddr-s.Seg.Vaddr, STYP_DWARF|subtype) 481 } 482 483 // xcoffGetDwarfSubtype returns the XCOFF name of the DWARF section str 484 // and its subtype constant. 485 func xcoffGetDwarfSubtype(str string) (string, uint32) { 486 switch str { 487 default: 488 Exitf("unknown DWARF section name for XCOFF: %s", str) 489 case ".debug_abbrev": 490 return ".dwabrev", SSUBTYP_DWABREV 491 case ".debug_info": 492 return ".dwinfo", SSUBTYP_DWINFO 493 case ".debug_frame": 494 return ".dwframe", SSUBTYP_DWFRAME 495 case ".debug_line": 496 return ".dwline", SSUBTYP_DWLINE 497 case ".debug_loc": 498 return ".dwloc", SSUBTYP_DWLOC 499 case ".debug_pubnames": 500 return ".dwpbnms", SSUBTYP_DWPBNMS 501 case ".debug_pubtypes": 502 return ".dwpbtyp", SSUBTYP_DWPBTYP 503 case ".debug_ranges": 504 return ".dwrnges", SSUBTYP_DWRNGES 505 } 506 // never used 507 return "", 0 508 } 509 510 // getXCOFFscnum returns the XCOFF section number of a Go section. 511 func (f *xcoffFile) getXCOFFscnum(sect *sym.Section) int16 { 512 switch sect.Seg { 513 case &Segtext: 514 return f.sectNameToScnum[".text"] 515 case &Segdata: 516 if sect.Name == ".noptrbss" || sect.Name == ".bss" { 517 return f.sectNameToScnum[".bss"] 518 } 519 if sect.Name == ".tbss" { 520 return f.sectNameToScnum[".tbss"] 521 } 522 return f.sectNameToScnum[".data"] 523 case &Segdwarf: 524 name, _ := xcoffGetDwarfSubtype(sect.Name) 525 return f.sectNameToScnum[name] 526 case &Segrelrodata: 527 return f.sectNameToScnum[".data"] 528 } 529 Errorf(nil, "getXCOFFscnum not implemented for section %s", sect.Name) 530 return -1 531 } 532 533 // Xcoffinit initialised some internal value and setups 534 // already known header information 535 func Xcoffinit(ctxt *Link) { 536 xfile.dynLibraries = make(map[string]int) 537 538 HEADR = int32(Rnd(XCOFFHDRRESERVE, XCOFFSECTALIGN)) 539 if *FlagTextAddr != -1 { 540 Errorf(nil, "-T not available on AIX") 541 } 542 *FlagTextAddr = XCOFFTEXTBASE + int64(HEADR) 543 if *FlagRound != -1 { 544 Errorf(nil, "-R not available on AIX") 545 } 546 *FlagRound = int(XCOFFSECTALIGN) 547 548 } 549 550 // SYMBOL TABLE 551 552 // type records C_FILE information needed for genasmsym in XCOFF. 553 type xcoffSymSrcFile struct { 554 name string 555 file *XcoffSymEnt64 // Symbol of this C_FILE 556 csectAux *XcoffAuxCSect64 // Symbol for the current .csect 557 csectSymNb uint64 // Symbol number for the current .csect 558 csectSize int64 559 } 560 561 var ( 562 currDwscnoff = make(map[string]uint64) // Needed to create C_DWARF symbols 563 currSymSrcFile xcoffSymSrcFile 564 outerSymSize = make(map[string]int64) 565 ) 566 567 // xcoffUpdateOuterSize stores the size of outer symbols in order to have it 568 // in the symbol table. 569 func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) { 570 if size == 0 { 571 return 572 } 573 574 switch stype { 575 default: 576 Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String()) 577 case sym.SRODATA, sym.SRODATARELRO, sym.SFUNCTAB, sym.SSTRING: 578 // Nothing to do 579 case sym.STYPERELRO: 580 if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) { 581 // runtime.types size must be removed, as it's a real symbol. 582 outerSymSize["typerel.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size 583 return 584 } 585 fallthrough 586 case sym.STYPE: 587 if !ctxt.DynlinkingGo() { 588 // runtime.types size must be removed, as it's a real symbol. 589 outerSymSize["type.*"] = size - ctxt.Syms.ROLookup("runtime.types", 0).Size 590 } 591 case sym.SGOSTRING: 592 outerSymSize["go.string.*"] = size 593 case sym.SGOFUNC: 594 if !ctxt.DynlinkingGo() { 595 outerSymSize["go.func.*"] = size 596 } 597 case sym.SGOFUNCRELRO: 598 outerSymSize["go.funcrel.*"] = size 599 case sym.SGCBITS: 600 outerSymSize["runtime.gcbits.*"] = size 601 case sym.SITABLINK: 602 outerSymSize["runtime.itablink"] = size 603 604 } 605 606 } 607 608 // addSymbol writes a symbol or an auxiliary symbol entry on ctxt.out. 609 func (f *xcoffFile) addSymbol(sym xcoffSym) { 610 f.symtabSym = append(f.symtabSym, sym) 611 f.symbolCount++ 612 } 613 614 // xcoffAlign returns the log base 2 of the symbol's alignment. 615 func xcoffAlign(x *sym.Symbol, t SymbolType) uint8 { 616 align := x.Align 617 if align == 0 { 618 if t == TextSym { 619 align = int32(Funcalign) 620 } else { 621 align = symalign(x) 622 } 623 } 624 return logBase2(int(align)) 625 } 626 627 // logBase2 returns the log in base 2 of a. 628 func logBase2(a int) uint8 { 629 return uint8(bits.Len(uint(a)) - 1) 630 } 631 632 // Write symbols needed when a new file appeared: 633 // - a C_FILE with one auxiliary entry for its name 634 // - C_DWARF symbols to provide debug information 635 // - a C_HIDEXT which will be a csect containing all of its functions 636 // It needs several parameters to create .csect symbols such as its entry point and its section number. 637 // 638 // Currently, a new file is in fact a new package. It seems to be OK, but it might change 639 // in the future. 640 func (f *xcoffFile) writeSymbolNewFile(ctxt *Link, name string, firstEntry uint64, extnum int16) { 641 /* C_FILE */ 642 s := &XcoffSymEnt64{ 643 Noffset: uint32(f.stringTable.add(".file")), 644 Nsclass: C_FILE, 645 Nscnum: N_DEBUG, 646 Ntype: 0, // Go isn't inside predefined language. 647 Nnumaux: 1, 648 } 649 f.addSymbol(s) 650 currSymSrcFile.file = s 651 652 // Auxiliary entry for file name. 653 auxf := &XcoffAuxFile64{ 654 Xoffset: uint32(f.stringTable.add(name)), 655 Xftype: XFT_FN, 656 Xauxtype: _AUX_FILE, 657 } 658 f.addSymbol(auxf) 659 660 /* Dwarf */ 661 for _, sect := range Segdwarf.Sections { 662 var dwsize uint64 663 if ctxt.LinkMode == LinkInternal { 664 // Find the size of this corresponding package DWARF compilation unit. 665 // This size is set during DWARF generation (see dwarf.go). 666 dwsize = getDwsectCUSize(sect.Name, name) 667 // .debug_abbrev is common to all packages and not found with the previous function 668 if sect.Name == ".debug_abbrev" { 669 s := ctxt.Syms.ROLookup(sect.Name, 0) 670 dwsize = uint64(s.Size) 671 672 } 673 } else { 674 // There is only one .FILE with external linking. 675 dwsize = sect.Length 676 } 677 678 // get XCOFF name 679 name, _ := xcoffGetDwarfSubtype(sect.Name) 680 s := &XcoffSymEnt64{ 681 Nvalue: currDwscnoff[sect.Name], 682 Noffset: uint32(f.stringTable.add(name)), 683 Nsclass: C_DWARF, 684 Nscnum: f.getXCOFFscnum(sect), 685 Nnumaux: 1, 686 } 687 688 if currSymSrcFile.csectAux == nil { 689 // Dwarf relocations need the symbol number of .dw* symbols. 690 // It doesn't need to know it for each package, one is enough. 691 // currSymSrcFile.csectAux == nil means first package. 692 dws := ctxt.Syms.Lookup(sect.Name, 0) 693 dws.Dynid = int32(f.symbolCount) 694 695 if sect.Name == ".debug_frame" && ctxt.LinkMode != LinkExternal { 696 // CIE size must be added to the first package. 697 dwsize += 48 698 } 699 } 700 701 f.addSymbol(s) 702 703 // update the DWARF section offset in this file 704 if sect.Name != ".debug_abbrev" { 705 currDwscnoff[sect.Name] += dwsize 706 } 707 708 // Auxiliary dwarf section 709 auxd := &XcoffAuxDWARF64{ 710 Xscnlen: dwsize, 711 Xauxtype: _AUX_SECT, 712 } 713 714 f.addSymbol(auxd) 715 } 716 717 /* .csect */ 718 // Check if extnum is in text. 719 // This is temporary and only here to check if this algorithm is correct. 720 if extnum != 1 { 721 Exitf("XCOFF symtab: A new file was detected with its first symbol not in .text") 722 } 723 724 currSymSrcFile.csectSymNb = uint64(f.symbolCount) 725 726 // No offset because no name 727 s = &XcoffSymEnt64{ 728 Nvalue: firstEntry, 729 Nscnum: extnum, 730 Nsclass: C_HIDEXT, 731 Ntype: 0, // check visibility ? 732 Nnumaux: 1, 733 } 734 f.addSymbol(s) 735 736 aux := &XcoffAuxCSect64{ 737 Xsmclas: XMC_PR, 738 Xsmtyp: XTY_SD | logBase2(Funcalign)<<3, 739 Xauxtype: _AUX_CSECT, 740 } 741 f.addSymbol(aux) 742 743 currSymSrcFile.csectAux = aux 744 currSymSrcFile.csectSize = 0 745 } 746 747 // Update values for the previous package. 748 // - Svalue of the C_FILE symbol: if it is the last one, this Svalue must be -1 749 // - Xsclen of the csect symbol. 750 func (f *xcoffFile) updatePreviousFile(ctxt *Link, last bool) { 751 // first file 752 if currSymSrcFile.file == nil { 753 return 754 } 755 756 // Update C_FILE 757 cfile := currSymSrcFile.file 758 if last { 759 cfile.Nvalue = 0xFFFFFFFFFFFFFFFF 760 } else { 761 cfile.Nvalue = uint64(f.symbolCount) 762 } 763 764 // update csect scnlen in this auxiliary entry 765 aux := currSymSrcFile.csectAux 766 aux.Xscnlenlo = uint32(currSymSrcFile.csectSize & 0xFFFFFFFF) 767 aux.Xscnlenhi = uint32(currSymSrcFile.csectSize >> 32) 768 } 769 770 // Write symbol representing a .text function. 771 // The symbol table is split with C_FILE corresponding to each package 772 // and not to each source file as it should be. 773 func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym { 774 // New XCOFF symbols which will be written. 775 syms := []xcoffSym{} 776 777 // Check if a new file is detected. 778 if strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") { 779 // Trampoline don't have a FILE so there are considered 780 // in the current file. 781 // Same goes for runtime.text.X symbols. 782 } else if x.File == "" { // Undefined global symbol 783 // If this happens, the algorithm must be redone. 784 if currSymSrcFile.name != "" { 785 Exitf("undefined global symbol found inside another file") 786 } 787 } else { 788 // Current file has changed. New C_FILE, C_DWARF, etc must be generated. 789 if currSymSrcFile.name != x.File { 790 if ctxt.LinkMode == LinkInternal { 791 // update previous file values 792 xfile.updatePreviousFile(ctxt, false) 793 currSymSrcFile.name = x.File 794 f.writeSymbolNewFile(ctxt, x.File, uint64(x.Value), xfile.getXCOFFscnum(x.Sect)) 795 } else { 796 // With external linking, ld will crash if there is several 797 // .FILE and DWARF debugging enable, somewhere during 798 // the relocation phase. 799 // Therefore, all packages are merged under a fake .FILE 800 // "go_functions". 801 // TODO(aix); remove once ld has been fixed or the triggering 802 // relocation has been found and fixed. 803 if currSymSrcFile.name == "" { 804 currSymSrcFile.name = x.File 805 f.writeSymbolNewFile(ctxt, "go_functions", uint64(x.Value), xfile.getXCOFFscnum(x.Sect)) 806 } 807 } 808 809 } 810 } 811 812 s := &XcoffSymEnt64{ 813 Nsclass: C_EXT, 814 Noffset: uint32(xfile.stringTable.add(x.Extname())), 815 Nvalue: uint64(x.Value), 816 Nscnum: f.getXCOFFscnum(x.Sect), 817 Ntype: SYM_TYPE_FUNC, 818 Nnumaux: 2, 819 } 820 821 if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() { 822 s.Nsclass = C_HIDEXT 823 } 824 825 x.Dynid = int32(xfile.symbolCount) 826 syms = append(syms, s) 827 828 // Update current csect size 829 currSymSrcFile.csectSize += x.Size 830 831 // create auxiliary entries 832 a2 := &XcoffAuxFcn64{ 833 Xfsize: uint32(x.Size), 834 Xlnnoptr: 0, // TODO 835 Xendndx: xfile.symbolCount + 3, // this symbol + 2 aux entries 836 Xauxtype: _AUX_FCN, 837 } 838 syms = append(syms, a2) 839 840 a4 := &XcoffAuxCSect64{ 841 Xscnlenlo: uint32(currSymSrcFile.csectSymNb & 0xFFFFFFFF), 842 Xscnlenhi: uint32(currSymSrcFile.csectSymNb >> 32), 843 Xsmclas: XMC_PR, // Program Code 844 Xsmtyp: XTY_LD, // label definition (based on C) 845 Xauxtype: _AUX_CSECT, 846 } 847 a4.Xsmtyp |= uint8(xcoffAlign(x, TextSym) << 3) 848 849 syms = append(syms, a4) 850 return syms 851 } 852 853 // put function used by genasmsym to write symbol table 854 func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, go_ *sym.Symbol) { 855 856 // All XCOFF symbols generated by this GO symbols 857 // Can be a symbol entry or a auxiliary entry 858 syms := []xcoffSym{} 859 860 switch t { 861 default: 862 return 863 864 case TextSym: 865 if x.FuncInfo != nil || strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") { 866 // Function within a file 867 syms = xfile.writeSymbolFunc(ctxt, x) 868 } else { 869 // Only runtime.text and runtime.etext come through this way 870 if x.Name != "runtime.text" && x.Name != "runtime.etext" && x.Name != "go.buildid" { 871 Exitf("putaixsym: unknown text symbol %s", x.Name) 872 } 873 s := &XcoffSymEnt64{ 874 Nsclass: C_HIDEXT, 875 Noffset: uint32(xfile.stringTable.add(str)), 876 Nvalue: uint64(x.Value), 877 Nscnum: xfile.getXCOFFscnum(x.Sect), 878 Ntype: SYM_TYPE_FUNC, 879 Nnumaux: 1, 880 } 881 x.Dynid = int32(xfile.symbolCount) 882 syms = append(syms, s) 883 884 size := uint64(x.Size) 885 a4 := &XcoffAuxCSect64{ 886 Xauxtype: _AUX_CSECT, 887 Xscnlenlo: uint32(size & 0xFFFFFFFF), 888 Xscnlenhi: uint32(size >> 32), 889 Xsmclas: XMC_PR, 890 Xsmtyp: XTY_SD, 891 } 892 a4.Xsmtyp |= uint8(xcoffAlign(x, TextSym) << 3) 893 syms = append(syms, a4) 894 895 } 896 897 case DataSym, BSSSym: 898 s := &XcoffSymEnt64{ 899 Nsclass: C_EXT, 900 Noffset: uint32(xfile.stringTable.add(str)), 901 Nvalue: uint64(x.Value), 902 Nscnum: xfile.getXCOFFscnum(x.Sect), 903 Nnumaux: 1, 904 } 905 906 if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() { 907 // There is more symbols in the case of a global data 908 // which are related to the assembly generated 909 // to access such symbols. 910 // But as Golang as its own way to check if a symbol is 911 // global or local (the capital letter), we don't need to 912 // implement them yet. 913 s.Nsclass = C_HIDEXT 914 } 915 916 x.Dynid = int32(xfile.symbolCount) 917 syms = append(syms, s) 918 919 // Create auxiliary entry 920 921 // Normally, size should be the size of csect containing all 922 // the data and bss symbols of one file/package. 923 // However, it's easier to just have a csect for each symbol. 924 // It might change 925 size := uint64(x.Size) 926 a4 := &XcoffAuxCSect64{ 927 Xauxtype: _AUX_CSECT, 928 Xscnlenlo: uint32(size & 0xFFFFFFFF), 929 Xscnlenhi: uint32(size >> 32), 930 } 931 932 if x.Type >= sym.STYPE && x.Type <= sym.SPCLNTAB { 933 if ctxt.LinkMode == LinkExternal && strings.HasPrefix(x.Sect.Name, ".data.rel.ro") { 934 // During external linking, read-only datas with relocation 935 // must be in .data. 936 a4.Xsmclas = XMC_RW 937 } else { 938 // Read only data 939 a4.Xsmclas = XMC_RO 940 } 941 } else if x.Type == sym.SDATA && strings.HasPrefix(x.Name, "TOC.") && ctxt.LinkMode == LinkExternal { 942 a4.Xsmclas = XMC_TC 943 } else if x.Name == "TOC" { 944 a4.Xsmclas = XMC_TC0 945 } else { 946 a4.Xsmclas = XMC_RW 947 } 948 if t == DataSym { 949 a4.Xsmtyp |= XTY_SD 950 } else { 951 a4.Xsmtyp |= XTY_CM 952 } 953 954 a4.Xsmtyp |= uint8(xcoffAlign(x, t) << 3) 955 956 syms = append(syms, a4) 957 958 case UndefinedSym: 959 if x.Type != sym.SDYNIMPORT && x.Type != sym.SHOSTOBJ && x.Type != sym.SUNDEFEXT { 960 return 961 } 962 s := &XcoffSymEnt64{ 963 Nsclass: C_EXT, 964 Noffset: uint32(xfile.stringTable.add(str)), 965 Nnumaux: 1, 966 } 967 x.Dynid = int32(xfile.symbolCount) 968 syms = append(syms, s) 969 970 a4 := &XcoffAuxCSect64{ 971 Xauxtype: _AUX_CSECT, 972 Xsmclas: XMC_DS, 973 Xsmtyp: XTY_ER | XTY_IMP, 974 } 975 976 if x.Name == "__n_pthreads" { 977 // Currently, all imported symbols made by cgo_import_dynamic are 978 // syscall functions, except __n_pthreads which is a variable. 979 // TODO(aix): Find a way to detect variables imported by cgo. 980 a4.Xsmclas = XMC_RW 981 } 982 983 syms = append(syms, a4) 984 985 case TLSSym: 986 s := &XcoffSymEnt64{ 987 Nsclass: C_EXT, 988 Noffset: uint32(xfile.stringTable.add(str)), 989 Nscnum: xfile.getXCOFFscnum(x.Sect), 990 Nvalue: uint64(x.Value), 991 Nnumaux: 1, 992 } 993 994 x.Dynid = int32(xfile.symbolCount) 995 syms = append(syms, s) 996 997 size := uint64(x.Size) 998 a4 := &XcoffAuxCSect64{ 999 Xauxtype: _AUX_CSECT, 1000 Xsmclas: XMC_UL, 1001 Xsmtyp: XTY_CM, 1002 Xscnlenlo: uint32(size & 0xFFFFFFFF), 1003 Xscnlenhi: uint32(size >> 32), 1004 } 1005 1006 syms = append(syms, a4) 1007 } 1008 1009 for _, s := range syms { 1010 xfile.addSymbol(s) 1011 } 1012 } 1013 1014 // Generate XCOFF Symbol table. 1015 // It will be written in out file in Asmbxcoff, because it must be 1016 // at the very end, especially after relocation sections which needs symbols' index. 1017 func (f *xcoffFile) asmaixsym(ctxt *Link) { 1018 // Get correct size for symbols wrapping others symbols like go.string.* 1019 // sym.Size can be used directly as the symbols have already been written. 1020 for name, size := range outerSymSize { 1021 sym := ctxt.Syms.ROLookup(name, 0) 1022 if sym == nil { 1023 Errorf(nil, "unknown outer symbol with name %s", name) 1024 } else { 1025 sym.Size = size 1026 } 1027 } 1028 1029 genasmsym(ctxt, putaixsym) 1030 xfile.updatePreviousFile(ctxt, true) 1031 } 1032 1033 func (f *xcoffFile) genDynSym(ctxt *Link) { 1034 var dynsyms []*sym.Symbol 1035 for _, s := range ctxt.Syms.Allsym { 1036 if s.Type != sym.SHOSTOBJ && s.Type != sym.SDYNIMPORT { 1037 continue 1038 } 1039 dynsyms = append(dynsyms, s) 1040 } 1041 1042 for _, s := range dynsyms { 1043 f.adddynimpsym(ctxt, s) 1044 1045 if _, ok := f.dynLibraries[s.Dynimplib()]; !ok { 1046 f.dynLibraries[s.Dynimplib()] = len(f.dynLibraries) 1047 } 1048 1049 } 1050 1051 } 1052 1053 // (*xcoffFile)adddynimpsym adds the dynamic symbol "s" to a XCOFF file. 1054 // A new symbol named s.Extname() is created to be the actual dynamic symbol 1055 // in the .loader section and in the symbol table as an External Reference. 1056 // The symbol "s" is transformed to SXCOFFTOC to end up in .data section. 1057 // However, there is no writing protection on those symbols and 1058 // it might need to be added. 1059 // TODO(aix): Handles dynamic symbols without library. 1060 func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) { 1061 // Check that library name is given. 1062 // Pattern is already checked when compiling. 1063 if ctxt.LinkMode == LinkInternal && s.Dynimplib() == "" { 1064 Errorf(s, "imported symbol must have a given library") 1065 } 1066 1067 s.Type = sym.SXCOFFTOC 1068 1069 // Create new dynamic symbol 1070 extsym := ctxt.Syms.Lookup(s.Extname(), 0) 1071 extsym.Type = sym.SDYNIMPORT 1072 extsym.Attr |= sym.AttrReachable 1073 extsym.SetDynimplib(s.Dynimplib()) 1074 extsym.SetExtname(s.Extname()) 1075 extsym.SetDynimpvers(s.Dynimpvers()) 1076 1077 // Add loader symbol 1078 lds := &xcoffLoaderSymbol{ 1079 sym: extsym, 1080 smtype: XTY_IMP, 1081 smclas: XMC_DS, 1082 } 1083 if s.Name == "__n_pthreads" { 1084 // Currently, all imported symbols made by cgo_import_dynamic are 1085 // syscall functions, except __n_pthreads which is a variable. 1086 // TODO(aix): Find a way to detect variables imported by cgo. 1087 lds.smclas = XMC_RW 1088 } 1089 f.loaderSymbols = append(f.loaderSymbols, lds) 1090 1091 // Relocation to retrieve the external address 1092 s.AddBytes(make([]byte, 8)) 1093 s.SetAddr(ctxt.Arch, 0, extsym) 1094 1095 } 1096 1097 // Xcoffadddynrel adds a dynamic relocation in a XCOFF file. 1098 // This relocation will be made by the loader. 1099 func Xcoffadddynrel(ctxt *Link, s *sym.Symbol, r *sym.Reloc) bool { 1100 if ctxt.LinkMode == LinkExternal { 1101 return true 1102 } 1103 if s.Type <= sym.SPCLNTAB { 1104 Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name) 1105 return false 1106 } 1107 1108 ldr := &xcoffLoaderReloc{ 1109 sym: s, 1110 rel: r, 1111 } 1112 1113 switch r.Type { 1114 default: 1115 Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", r.Sym.Name, r.Type.String()) 1116 return false 1117 case objabi.R_ADDR: 1118 if s.Type == sym.SXCOFFTOC && r.Sym.Type == sym.SDYNIMPORT { 1119 // Imported symbol relocation 1120 for i, dynsym := range xfile.loaderSymbols { 1121 if dynsym.sym.Name == r.Sym.Name { 1122 ldr.symndx = int32(i + 3) // +3 because of 3 section symbols 1123 break 1124 } 1125 } 1126 } else if s.Type == sym.SDATA { 1127 switch r.Sym.Sect.Seg { 1128 default: 1129 Errorf(s, "unknown segment for .loader relocation with symbol %s", r.Sym.Name) 1130 case &Segtext: 1131 case &Segrodata: 1132 ldr.symndx = 0 // .text 1133 case &Segdata: 1134 if r.Sym.Type == sym.SBSS || r.Sym.Type == sym.SNOPTRBSS { 1135 ldr.symndx = 2 // .bss 1136 } else { 1137 ldr.symndx = 1 // .data 1138 } 1139 1140 } 1141 1142 } else { 1143 Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", r.Sym.Name, s.Type, r.Sym.Type) 1144 return false 1145 } 1146 1147 ldr.rtype = 0x3F<<8 + XCOFF_R_POS 1148 } 1149 1150 xfile.loaderReloc = append(xfile.loaderReloc, ldr) 1151 return true 1152 } 1153 1154 func (ctxt *Link) doxcoff() { 1155 if *FlagD { 1156 // All XCOFF files have dynamic symbols because of the syscalls. 1157 Exitf("-d is not available on AIX") 1158 } 1159 1160 // TOC 1161 toc := ctxt.Syms.Lookup("TOC", 0) 1162 toc.Type = sym.SXCOFFTOC 1163 toc.Attr |= sym.AttrReachable 1164 toc.Attr |= sym.AttrVisibilityHidden 1165 1166 // Add entry point to .loader symbols. 1167 ep := ctxt.Syms.ROLookup(*flagEntrySymbol, 0) 1168 if !ep.Attr.Reachable() { 1169 Exitf("wrong entry point") 1170 } 1171 1172 xfile.loaderSymbols = append(xfile.loaderSymbols, &xcoffLoaderSymbol{ 1173 sym: ep, 1174 smtype: XTY_ENT | XTY_SD, 1175 smclas: XMC_DS, 1176 }) 1177 1178 xfile.genDynSym(ctxt) 1179 1180 for _, s := range ctxt.Syms.Allsym { 1181 if strings.HasPrefix(s.Name, "TOC.") { 1182 s.Type = sym.SXCOFFTOC 1183 } 1184 } 1185 1186 if ctxt.LinkMode == LinkExternal { 1187 // Change rt0_go name to match name in runtime/cgo:main(). 1188 rt0 := ctxt.Syms.ROLookup("runtime.rt0_go", 0) 1189 ctxt.Syms.Rename(rt0.Name, "runtime_rt0_go", 0, ctxt.Reachparent) 1190 1191 for _, s := range ctxt.Syms.Allsym { 1192 if !s.Attr.CgoExport() { 1193 continue 1194 } 1195 1196 name := s.Extname() 1197 if s.Type == sym.STEXT { 1198 // On AIX, a exported function must have two symbols: 1199 // - a .text symbol which must start with a ".". 1200 // - a .data symbol which is a function descriptor. 1201 ctxt.Syms.Rename(s.Name, "."+name, 0, ctxt.Reachparent) 1202 1203 desc := ctxt.Syms.Lookup(name, 0) 1204 desc.Type = sym.SNOPTRDATA 1205 desc.AddAddr(ctxt.Arch, s) 1206 desc.AddAddr(ctxt.Arch, toc) 1207 desc.AddUint64(ctxt.Arch, 0) 1208 } 1209 } 1210 } 1211 } 1212 1213 // Loader section 1214 // Currently, this section is created from scratch when assembling the XCOFF file 1215 // according to information retrieved in xfile object. 1216 1217 // Create loader section and returns its size 1218 func Loaderblk(ctxt *Link, off uint64) { 1219 xfile.writeLdrScn(ctxt, off) 1220 } 1221 1222 func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) { 1223 var symtab []*XcoffLdSym64 1224 var strtab []*XcoffLdStr64 1225 var importtab []*XcoffLdImportFile64 1226 var reloctab []*XcoffLdRel64 1227 var dynimpreloc []*XcoffLdRel64 1228 1229 // As the string table is updated in any loader subsection, 1230 // its length must be computed at the same time. 1231 stlen := uint32(0) 1232 1233 // Loader Header 1234 hdr := &XcoffLdHdr64{ 1235 Lversion: 2, 1236 Lsymoff: LDHDRSZ_64, 1237 } 1238 1239 /* Symbol table */ 1240 for _, s := range f.loaderSymbols { 1241 lds := &XcoffLdSym64{ 1242 Loffset: uint32(stlen + 2), 1243 Lsmtype: s.smtype, 1244 Lsmclas: s.smclas, 1245 } 1246 switch s.smtype { 1247 default: 1248 Errorf(s.sym, "unexpected loader symbol type: 0x%x", s.smtype) 1249 case XTY_ENT | XTY_SD: 1250 lds.Lvalue = uint64(s.sym.Value) 1251 lds.Lscnum = f.getXCOFFscnum(s.sym.Sect) 1252 case XTY_IMP: 1253 lds.Lifile = int32(f.dynLibraries[s.sym.Dynimplib()] + 1) 1254 } 1255 ldstr := &XcoffLdStr64{ 1256 size: uint16(len(s.sym.Name) + 1), // + null terminator 1257 name: s.sym.Name, 1258 } 1259 stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size 1260 symtab = append(symtab, lds) 1261 strtab = append(strtab, ldstr) 1262 1263 } 1264 1265 hdr.Lnsyms = int32(len(symtab)) 1266 hdr.Lrldoff = hdr.Lsymoff + uint64(24*hdr.Lnsyms) // 24 = sizeof one symbol 1267 off := hdr.Lrldoff // current offset is the same of reloc offset 1268 1269 /* Reloc */ 1270 ep := ctxt.Syms.ROLookup(*flagEntrySymbol, 0) 1271 ldr := &XcoffLdRel64{ 1272 Lvaddr: uint64(ep.Value), 1273 Lrtype: 0x3F00, 1274 Lrsecnm: f.getXCOFFscnum(ep.Sect), 1275 Lsymndx: 0, 1276 } 1277 off += 16 1278 reloctab = append(reloctab, ldr) 1279 1280 off += uint64(16 * len(f.loaderReloc)) 1281 for _, r := range f.loaderReloc { 1282 ldr = &XcoffLdRel64{ 1283 Lvaddr: uint64(r.sym.Value + int64(r.rel.Off)), 1284 Lrtype: r.rtype, 1285 Lsymndx: r.symndx, 1286 } 1287 1288 if r.sym.Sect != nil { 1289 ldr.Lrsecnm = f.getXCOFFscnum(r.sym.Sect) 1290 } 1291 1292 reloctab = append(reloctab, ldr) 1293 } 1294 1295 off += uint64(16 * len(dynimpreloc)) 1296 reloctab = append(reloctab, dynimpreloc...) 1297 1298 hdr.Lnreloc = int32(len(reloctab)) 1299 hdr.Limpoff = off 1300 1301 /* Import */ 1302 // Default import: /usr/lib:/lib 1303 ldimpf := &XcoffLdImportFile64{ 1304 Limpidpath: "/usr/lib:/lib", 1305 } 1306 off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter 1307 importtab = append(importtab, ldimpf) 1308 1309 // The map created by adddynimpsym associates the name to a number 1310 // This number represents the librairie index (- 1) in this import files section 1311 // Therefore, they must be sorted before being put inside the section 1312 libsOrdered := make([]string, len(f.dynLibraries)) 1313 for key, val := range f.dynLibraries { 1314 if libsOrdered[val] != "" { 1315 continue 1316 } 1317 libsOrdered[val] = key 1318 } 1319 1320 for _, lib := range libsOrdered { 1321 // lib string is defined as base.a/mem.o or path/base.a/mem.o 1322 n := strings.Split(lib, "/") 1323 path := "" 1324 base := n[len(n)-2] 1325 mem := n[len(n)-1] 1326 if len(n) > 2 { 1327 path = lib[:len(lib)-len(base)-len(mem)-2] 1328 1329 } 1330 ldimpf = &XcoffLdImportFile64{ 1331 Limpidpath: path, 1332 Limpidbase: base, 1333 Limpidmem: mem, 1334 } 1335 off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter 1336 importtab = append(importtab, ldimpf) 1337 } 1338 1339 hdr.Lnimpid = int32(len(importtab)) 1340 hdr.Listlen = uint32(off - hdr.Limpoff) 1341 hdr.Lstoff = off 1342 hdr.Lstlen = stlen 1343 1344 /* Writing */ 1345 ctxt.Out.SeekSet(int64(globalOff)) 1346 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, hdr) 1347 1348 for _, s := range symtab { 1349 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s) 1350 1351 } 1352 for _, r := range reloctab { 1353 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, r) 1354 } 1355 for _, f := range importtab { 1356 ctxt.Out.WriteString(f.Limpidpath) 1357 ctxt.Out.Write8(0) 1358 ctxt.Out.WriteString(f.Limpidbase) 1359 ctxt.Out.Write8(0) 1360 ctxt.Out.WriteString(f.Limpidmem) 1361 ctxt.Out.Write8(0) 1362 } 1363 for _, s := range strtab { 1364 ctxt.Out.Write16(s.size) 1365 ctxt.Out.WriteString(s.name) 1366 ctxt.Out.Write8(0) // null terminator 1367 } 1368 1369 f.loaderSize = off + uint64(stlen) 1370 ctxt.Out.Flush() 1371 1372 /* again for printing */ 1373 if !*flagA { 1374 return 1375 } 1376 1377 ctxt.Logf("\n.loader section") 1378 // write in buf 1379 var buf bytes.Buffer 1380 1381 binary.Write(&buf, ctxt.Arch.ByteOrder, hdr) 1382 for _, s := range symtab { 1383 binary.Write(&buf, ctxt.Arch.ByteOrder, s) 1384 1385 } 1386 for _, f := range importtab { 1387 buf.WriteString(f.Limpidpath) 1388 buf.WriteByte(0) 1389 buf.WriteString(f.Limpidbase) 1390 buf.WriteByte(0) 1391 buf.WriteString(f.Limpidmem) 1392 buf.WriteByte(0) 1393 } 1394 for _, s := range strtab { 1395 binary.Write(&buf, ctxt.Arch.ByteOrder, s.size) 1396 buf.WriteString(s.name) 1397 buf.WriteByte(0) // null terminator 1398 } 1399 1400 // Log buffer 1401 ctxt.Logf("\n\t%.8x|", globalOff) 1402 for i, b := range buf.Bytes() { 1403 if i > 0 && i%16 == 0 { 1404 ctxt.Logf("\n\t%.8x|", uint64(globalOff)+uint64(i)) 1405 } 1406 ctxt.Logf(" %.2x", b) 1407 } 1408 ctxt.Logf("\n") 1409 1410 } 1411 1412 // XCOFF assembling and writing file 1413 1414 func (f *xcoffFile) writeFileHeader(ctxt *Link) { 1415 // File header 1416 f.xfhdr.Fmagic = U64_TOCMAGIC 1417 f.xfhdr.Fnscns = uint16(len(f.sections)) 1418 f.xfhdr.Ftimedat = 0 1419 1420 if !*FlagS { 1421 f.xfhdr.Fsymptr = uint64(f.symtabOffset) 1422 f.xfhdr.Fnsyms = int32(f.symbolCount) 1423 } 1424 1425 if ctxt.BuildMode == BuildModeExe && ctxt.LinkMode == LinkInternal { 1426 f.xfhdr.Fopthdr = AOUTHSZ_EXEC64 1427 f.xfhdr.Fflags = F_EXEC 1428 1429 // auxiliary header 1430 f.xahdr.Ovstamp = 1 // based on dump -o 1431 f.xahdr.Omagic = 0x10b 1432 copy(f.xahdr.Omodtype[:], "1L") 1433 entry := ctxt.Syms.ROLookup(*flagEntrySymbol, 0) 1434 f.xahdr.Oentry = uint64(entry.Value) 1435 f.xahdr.Osnentry = f.getXCOFFscnum(entry.Sect) 1436 toc := ctxt.Syms.ROLookup("TOC", 0) 1437 f.xahdr.Otoc = uint64(toc.Value) 1438 f.xahdr.Osntoc = f.getXCOFFscnum(toc.Sect) 1439 1440 f.xahdr.Oalgntext = int16(logBase2(int(Funcalign))) 1441 f.xahdr.Oalgndata = 0x5 1442 1443 binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr) 1444 binary.Write(ctxt.Out, binary.BigEndian, &f.xahdr) 1445 } else { 1446 f.xfhdr.Fopthdr = 0 1447 binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr) 1448 } 1449 1450 } 1451 1452 func xcoffwrite(ctxt *Link) { 1453 ctxt.Out.SeekSet(0) 1454 1455 xfile.writeFileHeader(ctxt) 1456 1457 for _, sect := range xfile.sections { 1458 sect.write(ctxt) 1459 } 1460 } 1461 1462 // Generate XCOFF assembly file 1463 func Asmbxcoff(ctxt *Link, fileoff int64) { 1464 xfile.sectNameToScnum = make(map[string]int16) 1465 1466 // Add sections 1467 s := xfile.addSection(".text", Segtext.Vaddr, Segtext.Length, Segtext.Fileoff, STYP_TEXT) 1468 xfile.xahdr.Otextstart = s.Svaddr 1469 xfile.xahdr.Osntext = xfile.sectNameToScnum[".text"] 1470 xfile.xahdr.Otsize = s.Ssize 1471 xfile.sectText = s 1472 1473 segdataVaddr := Segdata.Vaddr 1474 segdataFilelen := Segdata.Filelen 1475 segdataFileoff := Segdata.Fileoff 1476 segbssFilelen := Segdata.Length - Segdata.Filelen 1477 if len(Segrelrodata.Sections) > 0 { 1478 // Merge relro segment to data segment as 1479 // relro data are inside data segment on AIX. 1480 segdataVaddr = Segrelrodata.Vaddr 1481 segdataFileoff = Segrelrodata.Fileoff 1482 segdataFilelen = Segdata.Vaddr + Segdata.Filelen - Segrelrodata.Vaddr 1483 } 1484 1485 s = xfile.addSection(".data", segdataVaddr, segdataFilelen, segdataFileoff, STYP_DATA) 1486 xfile.xahdr.Odatastart = s.Svaddr 1487 xfile.xahdr.Osndata = xfile.sectNameToScnum[".data"] 1488 xfile.xahdr.Odsize = s.Ssize 1489 xfile.sectData = s 1490 1491 s = xfile.addSection(".bss", segdataVaddr+segdataFilelen, segbssFilelen, 0, STYP_BSS) 1492 xfile.xahdr.Osnbss = xfile.sectNameToScnum[".bss"] 1493 xfile.xahdr.Obsize = s.Ssize 1494 xfile.sectBss = s 1495 1496 if ctxt.LinkMode == LinkExternal { 1497 var tbss *sym.Section 1498 for _, s := range Segdata.Sections { 1499 if s.Name == ".tbss" { 1500 tbss = s 1501 break 1502 } 1503 } 1504 s = xfile.addSection(".tbss", tbss.Vaddr, tbss.Length, 0, STYP_TBSS) 1505 } 1506 1507 // add dwarf sections 1508 for _, sect := range Segdwarf.Sections { 1509 xfile.addDwarfSection(sect) 1510 } 1511 1512 // add and write remaining sections 1513 if ctxt.LinkMode == LinkInternal { 1514 // Loader section 1515 if ctxt.BuildMode == BuildModeExe { 1516 Loaderblk(ctxt, uint64(fileoff)) 1517 s = xfile.addSection(".loader", 0, xfile.loaderSize, uint64(fileoff), STYP_LOADER) 1518 xfile.xahdr.Osnloader = xfile.sectNameToScnum[".loader"] 1519 1520 // Update fileoff for symbol table 1521 fileoff += int64(xfile.loaderSize) 1522 } 1523 } 1524 1525 // Create Symbol table 1526 xfile.asmaixsym(ctxt) 1527 1528 if ctxt.LinkMode == LinkExternal { 1529 xfile.emitRelocations(ctxt, fileoff) 1530 } 1531 1532 // Write Symbol table 1533 xfile.symtabOffset = ctxt.Out.Offset() 1534 for _, s := range xfile.symtabSym { 1535 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s) 1536 } 1537 // write string table 1538 xfile.stringTable.write(ctxt.Out) 1539 1540 ctxt.Out.Flush() 1541 1542 // write headers 1543 xcoffwrite(ctxt) 1544 } 1545 1546 // byOffset is used to sort relocations by offset 1547 type byOffset []sym.Reloc 1548 1549 func (x byOffset) Len() int { return len(x) } 1550 1551 func (x byOffset) Swap(i, j int) { 1552 x[i], x[j] = x[j], x[i] 1553 } 1554 1555 func (x byOffset) Less(i, j int) bool { 1556 return x[i].Off < x[j].Off 1557 } 1558 1559 // emitRelocations emits relocation entries for go.o in external linking. 1560 func (f *xcoffFile) emitRelocations(ctxt *Link, fileoff int64) { 1561 ctxt.Out.SeekSet(fileoff) 1562 for ctxt.Out.Offset()&7 != 0 { 1563 ctxt.Out.Write8(0) 1564 } 1565 1566 // relocsect relocates symbols from first in section sect, and returns 1567 // the total number of relocations emitted. 1568 relocsect := func(sect *sym.Section, syms []*sym.Symbol, base uint64) uint32 { 1569 // ctxt.Logf("%s 0x%x\n", sect.Name, sect.Vaddr) 1570 // If main section has no bits, nothing to relocate. 1571 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 1572 return 0 1573 } 1574 sect.Reloff = uint64(ctxt.Out.Offset()) 1575 for i, s := range syms { 1576 if !s.Attr.Reachable() { 1577 continue 1578 } 1579 if uint64(s.Value) >= sect.Vaddr { 1580 syms = syms[i:] 1581 break 1582 } 1583 } 1584 eaddr := int64(sect.Vaddr + sect.Length) 1585 for _, s := range syms { 1586 if !s.Attr.Reachable() { 1587 continue 1588 } 1589 if s.Value >= int64(eaddr) { 1590 break 1591 } 1592 1593 // Relocation must be ordered by address, so s.R is ordered by Off. 1594 sort.Sort(byOffset(s.R)) 1595 1596 for ri := range s.R { 1597 1598 r := &s.R[ri] 1599 1600 if r.Done { 1601 continue 1602 } 1603 if r.Xsym == nil { 1604 Errorf(s, "missing xsym in relocation") 1605 continue 1606 } 1607 if r.Xsym.Dynid < 0 { 1608 Errorf(s, "reloc %s to non-coff symbol %s (outer=%s) %d %d", r.Type.String(), r.Sym.Name, r.Xsym.Name, r.Sym.Type, r.Xsym.Dynid) 1609 } 1610 if !thearch.Xcoffreloc1(ctxt.Arch, ctxt.Out, s, r, int64(uint64(s.Value+int64(r.Off))-base)) { 1611 Errorf(s, "unsupported obj reloc %d(%s)/%d to %s", r.Type, r.Type.String(), r.Siz, r.Sym.Name) 1612 } 1613 } 1614 } 1615 sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff 1616 return uint32(sect.Rellen) / RELSZ_64 1617 } 1618 sects := []struct { 1619 xcoffSect *XcoffScnHdr64 1620 segs []*sym.Segment 1621 }{ 1622 {f.sectText, []*sym.Segment{&Segtext}}, 1623 {f.sectData, []*sym.Segment{&Segrelrodata, &Segdata}}, 1624 } 1625 for _, s := range sects { 1626 s.xcoffSect.Srelptr = uint64(ctxt.Out.Offset()) 1627 n := uint32(0) 1628 for _, seg := range s.segs { 1629 for _, sect := range seg.Sections { 1630 if sect.Name == ".text" { 1631 n += relocsect(sect, ctxt.Textp, 0) 1632 } else { 1633 n += relocsect(sect, datap, 0) 1634 } 1635 } 1636 } 1637 s.xcoffSect.Snreloc += n 1638 } 1639 1640 dwarfLoop: 1641 for _, sect := range Segdwarf.Sections { 1642 for _, xcoffSect := range f.sections { 1643 _, subtyp := xcoffGetDwarfSubtype(sect.Name) 1644 if xcoffSect.Sflags&0xF0000 == subtyp { 1645 xcoffSect.Srelptr = uint64(ctxt.Out.Offset()) 1646 xcoffSect.Snreloc = relocsect(sect, dwarfp, sect.Vaddr) 1647 continue dwarfLoop 1648 } 1649 } 1650 Errorf(nil, "emitRelocations: could not find %q section", sect.Name) 1651 } 1652 } 1653 1654 // xcoffCreateExportFile creates a file with exported symbols for 1655 // -Wl,-bE option. 1656 // ld won't export symbols unless they are listed in an export file. 1657 func xcoffCreateExportFile(ctxt *Link) (fname string) { 1658 fname = filepath.Join(*flagTmpdir, "export_file.exp") 1659 var buf bytes.Buffer 1660 1661 for _, s := range ctxt.Syms.Allsym { 1662 if !s.Attr.CgoExport() { 1663 continue 1664 } 1665 if !strings.HasPrefix(s.String(), "_cgoexp_") { 1666 continue 1667 } 1668 1669 // Retrieve the name of the initial symbol 1670 // exported by cgo. 1671 // The corresponding Go symbol is: 1672 // _cgoexp_hashcode_symname. 1673 name := strings.SplitN(s.Extname(), "_", 4)[3] 1674 1675 buf.Write([]byte(name + "\n")) 1676 } 1677 1678 err := ioutil.WriteFile(fname, buf.Bytes(), 0666) 1679 if err != nil { 1680 Errorf(nil, "WriteFile %s failed: %v", fname, err) 1681 } 1682 1683 return fname 1684 1685 }