github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/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 "cmd/internal/objabi" 10 "cmd/link/internal/sym" 11 "encoding/binary" 12 "strings" 13 ) 14 15 // This file handles all algorithms related to XCOFF files generation. 16 // Most of them are adaptations of the ones in cmd/link/internal/pe.go 17 // as PE and XCOFF are based on COFF files. 18 // XCOFF files generated are 64 bits. 19 20 // Total amount of space to reserve at the start of the file 21 // for FileHeader, Auxiliary Header, and Section Headers. 22 // May waste some. 23 // Based on 24(fhdr) + 120(ahdr) + 23(max sections number) * 72(scnhdr) 24 const ( 25 XCOFFHDRRESERVE = FILHSZ_64 + AOUTHSZ_EXEC64 + SCNHSZ_64*23 26 ) 27 28 const ( 29 XCOFFSECTALIGN int64 = 32 // base on dump -o 30 XCOFFBASE = 0x100000000 // Address on 64 bits must start at this value. 31 ) 32 33 // File Header 34 type XcoffFileHdr64 struct { 35 Fmagic uint16 // Target machine 36 Fnscns uint16 // Number of sections 37 Ftimedat int32 // Time and date of file creation 38 Fsymptr uint64 // Byte offset to symbol table start 39 Fopthdr uint16 // Number of bytes in optional header 40 Fflags uint16 // Flags 41 Fnsyms int32 // Number of entries in symbol table 42 } 43 44 const ( 45 U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF 46 ) 47 48 // Flags that describe the type of the object file. 49 const ( 50 F_RELFLG = 0x0001 51 F_EXEC = 0x0002 52 F_LNNO = 0x0004 53 F_FDPR_PROF = 0x0010 54 F_FDPR_OPTI = 0x0020 55 F_DSA = 0x0040 56 F_VARPG = 0x0100 57 F_DYNLOAD = 0x1000 58 F_SHROBJ = 0x2000 59 F_LOADONLY = 0x4000 60 ) 61 62 // Auxiliary Header 63 type XcoffAoutHdr64 struct { 64 Omagic int16 // Flags - Ignored If Vstamp Is 1 65 Ovstamp int16 // Version 66 Odebugger uint32 // Reserved For Debugger 67 Otextstart uint64 // Virtual Address Of Text 68 Odatastart uint64 // Virtual Address Of Data 69 Otoc uint64 // Toc Address 70 Osnentry int16 // Section Number For Entry Point 71 Osntext int16 // Section Number For Text 72 Osndata int16 // Section Number For Data 73 Osntoc int16 // Section Number For Toc 74 Osnloader int16 // Section Number For Loader 75 Osnbss int16 // Section Number For Bss 76 Oalgntext int16 // Max Text Alignment 77 Oalgndata int16 // Max Data Alignment 78 Omodtype [2]byte // Module Type Field 79 Ocpuflag uint8 // Bit Flags - Cputypes Of Objects 80 Ocputype uint8 // Reserved for CPU type 81 Otextpsize uint8 // Requested text page size 82 Odatapsize uint8 // Requested data page size 83 Ostackpsize uint8 // Requested stack page size 84 Oflags uint8 // Flags And TLS Alignment 85 Otsize uint64 // Text Size In Bytes 86 Odsize uint64 // Data Size In Bytes 87 Obsize uint64 // Bss Size In Bytes 88 Oentry uint64 // Entry Point Address 89 Omaxstack uint64 // Max Stack Size Allowed 90 Omaxdata uint64 // Max Data Size Allowed 91 Osntdata int16 // Section Number For Tdata Section 92 Osntbss int16 // Section Number For Tbss Section 93 Ox64flags uint16 // Additional Flags For 64-Bit Objects 94 Oresv3a int16 // Reserved 95 Oresv3 [2]int32 // Reserved 96 97 } 98 99 // Section Header 100 type XcoffScnHdr64 struct { 101 Sname [8]byte // Section Name 102 Spaddr uint64 // Physical Address 103 Svaddr uint64 // Virtual Address 104 Ssize uint64 // Section Size 105 Sscnptr uint64 // File Offset To Raw Data 106 Srelptr uint64 // File Offset To Relocation 107 Slnnoptr uint64 // File Offset To Line Numbers 108 Snreloc uint32 // Number Of Relocation Entries 109 Snlnno uint32 // Number Of Line Number Entries 110 Sflags uint32 // flags 111 } 112 113 // Flags defining the section type. 114 const ( 115 STYP_DWARF = 0x0010 116 STYP_TEXT = 0x0020 117 STYP_DATA = 0x0040 118 STYP_BSS = 0x0080 119 STYP_EXCEPT = 0x0100 120 STYP_INFO = 0x0200 121 STYP_TDATA = 0x0400 122 STYP_TBSS = 0x0800 123 STYP_LOADER = 0x1000 124 STYP_DEBUG = 0x2000 125 STYP_TYPCHK = 0x4000 126 STYP_OVRFLO = 0x8000 127 ) 128 const ( 129 SSUBTYP_DWINFO = 0x10000 // DWARF info section 130 SSUBTYP_DWLINE = 0x20000 // DWARF line-number section 131 SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section 132 SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section 133 SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section 134 SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section 135 SSUBTYP_DWSTR = 0x70000 // DWARF strings section 136 SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section 137 SSUBTYP_DWLOC = 0x90000 // DWARF location lists section 138 SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section 139 SSUBTYP_DWMAC = 0xB0000 // DWARF macros section 140 ) 141 142 // Headers size 143 const ( 144 FILHSZ_32 = 20 145 FILHSZ_64 = 24 146 AOUTHSZ_EXEC32 = 72 147 AOUTHSZ_EXEC64 = 120 148 SCNHSZ_32 = 40 149 SCNHSZ_64 = 72 150 LDHDRSZ_32 = 32 151 LDHDRSZ_64 = 56 152 LDSYMSZ_64 = 24 153 ) 154 155 // Symbol Table Entry 156 type XcoffSymEnt64 struct { 157 Nvalue uint64 // Symbol value 158 Noffset uint32 // Offset of the name in string table or .debug section 159 Nscnum int16 // Section number of symbol 160 Ntype uint16 // Basic and derived type specification 161 Nsclass uint8 // Storage class of symbol 162 Nnumaux int8 // Number of auxiliary entries 163 } 164 165 const SYMESZ = 18 166 167 const ( 168 // Nscnum 169 N_DEBUG = -2 170 N_ABS = -1 171 N_UNDEF = 0 172 173 //Ntype 174 SYM_V_INTERNAL = 0x1000 175 SYM_V_HIDDEN = 0x2000 176 SYM_V_PROTECTED = 0x3000 177 SYM_V_EXPORTED = 0x4000 178 SYM_TYPE_FUNC = 0x0020 // is function 179 ) 180 181 // Storage Class. 182 const ( 183 C_NULL = 0 // Symbol table entry marked for deletion 184 C_EXT = 2 // External symbol 185 C_STAT = 3 // Static symbol 186 C_BLOCK = 100 // Beginning or end of inner block 187 C_FCN = 101 // Beginning or end of function 188 C_FILE = 103 // Source file name and compiler information 189 C_HIDEXT = 107 // Unnamed external symbol 190 C_BINCL = 108 // Beginning of include file 191 C_EINCL = 109 // End of include file 192 C_WEAKEXT = 111 // Weak external symbol 193 C_DWARF = 112 // DWARF symbol 194 C_GSYM = 128 // Global variable 195 C_LSYM = 129 // Automatic variable allocated on stack 196 C_PSYM = 130 // Argument to subroutine allocated on stack 197 C_RSYM = 131 // Register variable 198 C_RPSYM = 132 // Argument to function or procedure stored in register 199 C_STSYM = 133 // Statically allocated symbol 200 C_BCOMM = 135 // Beginning of common block 201 C_ECOML = 136 // Local member of common block 202 C_ECOMM = 137 // End of common block 203 C_DECL = 140 // Declaration of object 204 C_ENTRY = 141 // Alternate entry 205 C_FUN = 142 // Function or procedure 206 C_BSTAT = 143 // Beginning of static block 207 C_ESTAT = 144 // End of static block 208 C_GTLS = 145 // Global thread-local variable 209 C_STTLS = 146 // Static thread-local variable 210 ) 211 212 // File Auxiliary Entry 213 type XcoffAuxFile64 struct { 214 Xfname [8]byte // Name or offset inside string table 215 Xftype uint8 // Source file string type 216 Xauxtype uint8 // Type of auxiliary entry 217 } 218 219 // Function Auxiliary Entry 220 type XcoffAuxFcn64 struct { 221 Xlnnoptr uint64 // File pointer to line number 222 Xfsize uint32 // Size of function in bytes 223 Xendndx uint32 // Symbol table index of next entry 224 Xpad uint8 // Unused 225 Xauxtype uint8 // Type of auxiliary entry 226 } 227 228 // csect Auxiliary Entry. 229 type XcoffAuxCSect64 struct { 230 Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index 231 Xparmhash uint32 // Offset of parameter type-check string 232 Xsnhash uint16 // .typchk section number 233 Xsmtyp uint8 // Symbol alignment and type 234 Xsmclas uint8 // Storage-mapping class 235 Xscnlenhi uint32 // Upper 4 bytes of length or symbol table index 236 Xpad uint8 // Unused 237 Xauxtype uint8 // Type of auxiliary entry 238 } 239 240 // Auxiliary type 241 const ( 242 _AUX_EXCEPT = 255 243 _AUX_FCN = 254 244 _AUX_SYM = 253 245 _AUX_FILE = 252 246 _AUX_CSECT = 251 247 _AUX_SECT = 250 248 ) 249 250 // Xftype field 251 const ( 252 XFT_FN = 0 // Source File Name 253 XFT_CT = 1 // Compile Time Stamp 254 XFT_CV = 2 // Compiler Version Number 255 XFT_CD = 128 // Compiler Defined Information/ 256 257 ) 258 259 // Symbol type field. 260 const ( 261 XTY_ER = 0 // External reference 262 XTY_SD = 1 // Section definition 263 XTY_LD = 2 // Label definition 264 XTY_CM = 3 // Common csect definition 265 XTY_WK = 0x8 // Weak symbol 266 XTY_EXP = 0x10 // Exported symbol 267 XTY_ENT = 0x20 // Entry point symbol 268 XTY_IMP = 0x40 // Imported symbol 269 ) 270 271 // Storage-mapping class. 272 const ( 273 XMC_PR = 0 // Program code 274 XMC_RO = 1 // Read-only constant 275 XMC_DB = 2 // Debug dictionary table 276 XMC_TC = 3 // TOC entry 277 XMC_UA = 4 // Unclassified 278 XMC_RW = 5 // Read/Write data 279 XMC_GL = 6 // Global linkage 280 XMC_XO = 7 // Extended operation 281 XMC_SV = 8 // 32-bit supervisor call descriptor 282 XMC_BS = 9 // BSS class 283 XMC_DS = 10 // Function descriptor 284 XMC_UC = 11 // Unnamed FORTRAN common 285 XMC_TC0 = 15 // TOC anchor 286 XMC_TD = 16 // Scalar data entry in the TOC 287 XMC_SV64 = 17 // 64-bit supervisor call descriptor 288 XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit 289 XMC_TL = 20 // Read/Write thread-local data 290 XMC_UL = 21 // Read/Write thread-local data (.tbss) 291 XMC_TE = 22 // TOC entry 292 ) 293 294 // Loader Header 295 type XcoffLdHdr64 struct { 296 Lversion int32 // Loader section version number 297 Lnsyms int32 // Number of symbol table entries 298 Lnreloc int32 // Number of relocation table entries 299 Listlen uint32 // Length of import file ID string table 300 Lnimpid int32 // Number of import file IDs 301 Lstlen uint32 // Length of string table 302 Limpoff uint64 // Offset to start of import file IDs 303 Lstoff uint64 // Offset to start of string table 304 Lsymoff uint64 // Offset to start of symbol table 305 Lrldoff uint64 // Offset to start of relocation entries 306 } 307 308 // Loader Symbol 309 type XcoffLdSym64 struct { 310 Lvalue uint64 // Address field 311 Loffset uint32 // Byte offset into string table of symbol name 312 Lscnum int16 // Section number containing symbol 313 Lsmtype int8 // Symbol type, export, import flags 314 Lsmclas int8 // Symbol storage class 315 Lifile int32 // Import file ID; ordinal of import file IDs 316 Lparm uint32 // Parameter type-check field 317 } 318 319 type XcoffLdImportFile64 struct { 320 Limpidpath string 321 Limpidbase string 322 Limpidmem string 323 } 324 325 type XcoffLdRel64 struct { 326 Lvaddr uint64 // Address Field 327 Lrtype uint16 // Relocation Size and Type 328 Lrsecnm int16 // Section Number being relocated 329 Lsymndx int32 // Loader-Section symbol table index 330 } 331 332 const ( 333 XCOFF_R_POS = 0x00 // A(sym) Positive Relocation 334 ) 335 336 type XcoffLdStr64 struct { 337 size uint16 338 name string 339 } 340 341 // xcoffFile is used to build XCOFF file. 342 type xcoffFile struct { 343 xfhdr XcoffFileHdr64 344 xahdr XcoffAoutHdr64 345 sections []*XcoffScnHdr64 346 stringTable xcoffStringTable 347 textSect *XcoffScnHdr64 348 dataSect *XcoffScnHdr64 349 bssSect *XcoffScnHdr64 350 loaderSect *XcoffScnHdr64 351 symtabOffset int64 // offset to the start of symbol table 352 symbolCount uint32 // number of symbol table records written 353 dynLibraries map[string]int // Dynamic libraries in .loader section. The integer represents its import file number (- 1) 354 dynSymbols []*sym.Symbol // Dynamic symbols in .loader section 355 loaderReloc []*XcoffLdRel64 // Reloc that must be made inside loader 356 } 357 358 // Those values will latter be computed in XcoffInit 359 var ( 360 XCOFFFILEHDR int 361 XCOFFSECTHDR int 362 ) 363 364 // Var used by XCOFF Generation algorithms 365 var ( 366 xfile xcoffFile 367 loaderOff uint64 368 loaderSize uint64 369 ) 370 371 // xcoffStringTable is a XCOFF string table. 372 type xcoffStringTable struct { 373 strings []string 374 stringsLen int 375 } 376 377 // size returns size of string table t. 378 func (t *xcoffStringTable) size() int { 379 // string table starts with 4-byte length at the beginning 380 return t.stringsLen + 4 381 } 382 383 // add adds string str to string table t. 384 func (t *xcoffStringTable) add(str string) int { 385 off := t.size() 386 t.strings = append(t.strings, str) 387 t.stringsLen += len(str) + 1 // each string will have 0 appended to it 388 return off 389 } 390 391 // write writes string table t into the output file. 392 func (t *xcoffStringTable) write(out *OutBuf) { 393 out.Write32(uint32(t.size())) 394 for _, s := range t.strings { 395 out.WriteString(s) 396 out.Write8(0) 397 } 398 } 399 400 // write writes XCOFF section sect into the output file. 401 func (sect *XcoffScnHdr64) write(ctxt *Link) { 402 binary.Write(ctxt.Out, binary.BigEndian, sect) 403 ctxt.Out.Write32(0) // Add 4 empty bytes at the end to match alignment 404 } 405 406 // addSection adds section to the XCOFF file f. 407 func (f *xcoffFile) addSection(s *sym.Section) *XcoffScnHdr64 { 408 sect := &XcoffScnHdr64{ 409 Spaddr: s.Vaddr, 410 Svaddr: s.Vaddr, 411 Ssize: s.Length, 412 Sscnptr: s.Seg.Fileoff + s.Vaddr - s.Seg.Vaddr, 413 } 414 copy(sect.Sname[:], s.Name) // copy string to [8]byte ( pb if len(name) > 8 ) 415 f.sections = append(f.sections, sect) 416 return sect 417 } 418 419 // addLoaderSection adds the loader section to the XCOFF file f. 420 func (f *xcoffFile) addLoaderSection(size uint64, off uint64) *XcoffScnHdr64 { 421 sect := &XcoffScnHdr64{ 422 Ssize: size, 423 Sscnptr: off, 424 Sflags: STYP_LOADER, 425 } 426 copy(sect.Sname[:], ".loader") // copy string to [8]byte ( pb if len(name) > 8 427 f.xahdr.Osnloader = int16(len(f.sections) + 1) 428 f.sections = append(f.sections, sect) 429 f.loaderSect = sect 430 return sect 431 } 432 433 // addDwarfSection adds a dwarf section to the XCOFF file f. 434 // This function is similar to addSection, but Dwarf section names 435 // must be modified to conventional names and they are various subtypes. 436 func (f *xcoffFile) addDwarfSection(s *sym.Section) *XcoffScnHdr64 { 437 sect := &XcoffScnHdr64{ 438 Ssize: s.Length, 439 Sscnptr: s.Seg.Fileoff + s.Vaddr - s.Seg.Vaddr, 440 Sflags: STYP_DWARF, 441 } 442 newName, subtype := xcoffGetDwarfSubtype(s.Name) 443 copy(sect.Sname[:], newName) 444 sect.Sflags |= subtype 445 f.sections = append(f.sections, sect) 446 return sect 447 } 448 449 // xcoffGetDwarfSubtype returns the XCOFF name of the DWARF section str 450 // and its subtype constant. 451 func xcoffGetDwarfSubtype(str string) (string, uint32) { 452 switch str { 453 default: 454 Exitf("unknown DWARF section name for XCOFF: %s", str) 455 case ".debug_abbrev": 456 return ".dwabrev", SSUBTYP_DWABREV 457 case ".debug_info": 458 return ".dwinfo", SSUBTYP_DWINFO 459 case ".debug_frame": 460 return ".dwframe", SSUBTYP_DWFRAME 461 case ".debug_line": 462 return ".dwline", SSUBTYP_DWLINE 463 case ".debug_loc": 464 return ".dwloc", SSUBTYP_DWLOC 465 case ".debug_pubnames": 466 return ".dwpbnms", SSUBTYP_DWPBNMS 467 case ".debug_pubtypes": 468 return ".dwpbtyp", SSUBTYP_DWPBTYP 469 case ".debug_ranges": 470 return ".dwrnge", SSUBTYP_DWRNGES 471 } 472 // never used 473 return "", 0 474 } 475 476 // Xcoffinit initialised some internal value and setups 477 // already known header information 478 func Xcoffinit(ctxt *Link) { 479 xfile.dynLibraries = make(map[string]int) 480 481 XCOFFFILEHDR = int(Rnd(XCOFFHDRRESERVE, XCOFFSECTALIGN)) 482 XCOFFSECTHDR = int(Rnd(int64(XCOFFFILEHDR), XCOFFSECTALIGN)) 483 484 HEADR = int32(XCOFFFILEHDR) 485 if *FlagTextAddr != -1 { 486 Errorf(nil, "-T not available on AIX") 487 } 488 *FlagTextAddr = XCOFFBASE + int64(XCOFFSECTHDR) 489 *FlagDataAddr = 0 490 if *FlagRound != -1 { 491 Errorf(nil, "-R not available on AIX") 492 } 493 *FlagRound = int(XCOFFSECTALIGN) 494 495 } 496 497 // SYMBOL TABLE 498 499 // type records C_FILE information needed for genasmsym in XCOFF. 500 type xcoffSymSrcFile struct { 501 name string 502 fileSymNb uint32 // Symbol number of this C_FILE 503 csectSymNb uint64 // Symbol number for the current .csect 504 csectSize int64 505 } 506 507 var ( 508 currDwscnoff = make(map[string]uint64) // Needed to create C_DWARF symbols 509 currSymSrcFile xcoffSymSrcFile 510 ) 511 512 // writeSymbol writes a symbol or an auxiliary symbol entry on ctxt.out. 513 func (f *xcoffFile) writeSymbol(out *OutBuf, byteOrder binary.ByteOrder, sym interface{}) { 514 binary.Write(out, byteOrder, sym) 515 f.symbolCount++ 516 } 517 518 // Write symbols needed when a new file appared : 519 // - a C_FILE with one auxiliary entry for its name 520 // - C_DWARF symbols to provide debug information 521 // - a C_HIDEXT which will be a csect containing all of its functions 522 // It needs several parameters to create .csect symbols such as its entry point and its section number. 523 // 524 // Currently, a new file is in fact a new package. It seems to be OK, but it might change 525 // in the future. 526 func (f *xcoffFile) writeSymbolNewFile(ctxt *Link, name string, firstEntry uint64, extnum int16) { 527 /* C_FILE */ 528 s := &XcoffSymEnt64{ 529 Noffset: uint32(f.stringTable.add(".file")), 530 Nsclass: C_FILE, 531 Nscnum: N_DEBUG, 532 Ntype: 0, // Go isn't inside predefined language. 533 Nnumaux: 1, 534 } 535 f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s) 536 537 // Auxiliary entry for file name. 538 ctxt.Out.Write32(0) 539 ctxt.Out.Write32(uint32(f.stringTable.add(name))) 540 ctxt.Out.Write32(0) // 6 bytes empty 541 ctxt.Out.Write16(0) 542 ctxt.Out.Write8(XFT_FN) 543 ctxt.Out.Write16(0) // 2 bytes empty 544 ctxt.Out.Write8(_AUX_FILE) 545 f.symbolCount++ 546 547 /* Dwarf */ 548 for _, sect := range Segdwarf.Sections { 549 // Find the size of this corresponding package DWARF compilation unit. 550 // This size is set during DWARF generation (see dwarf.go). 551 dwsize := getDwsectCUSize(sect.Name, name) 552 // .debug_abbrev is commun to all packages and not found with the previous function 553 if sect.Name == ".debug_abbrev" { 554 s := ctxt.Syms.Lookup(sect.Name, 0) 555 dwsize = uint64(s.Size) 556 } 557 558 // get XCOFF name 559 name, _ := xcoffGetDwarfSubtype(sect.Name) 560 s := &XcoffSymEnt64{ 561 Nvalue: currDwscnoff[sect.Name], 562 Noffset: uint32(f.stringTable.add(name)), 563 Nsclass: C_DWARF, 564 Nscnum: sect.Extnum, 565 Nnumaux: 1, 566 } 567 f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s) 568 569 // update the DWARF section offset in this file 570 if sect.Name != ".debug_abbrev" { 571 currDwscnoff[sect.Name] += dwsize 572 } 573 574 // Auxiliary dwarf section 575 ctxt.Out.Write64(dwsize) // section length 576 ctxt.Out.Write64(0) // nreloc 577 ctxt.Out.Write8(0) // pad 578 ctxt.Out.Write8(_AUX_SECT) 579 f.symbolCount++ 580 } 581 582 /* .csect */ 583 // Check if extnum is in text. 584 // This is temporary and only here to check if this algorithm is correct. 585 if extnum != 1 { 586 Exitf("XCOFF symtab: A new file was detected with its first symbol not in .text") 587 } 588 589 currSymSrcFile.csectSymNb = uint64(f.symbolCount) 590 currSymSrcFile.csectSize = 0 591 592 // No offset because no name 593 s = &XcoffSymEnt64{ 594 Nvalue: firstEntry, 595 Nscnum: extnum, 596 Nsclass: C_HIDEXT, 597 Ntype: 0, // check visibility ? 598 Nnumaux: 1, 599 } 600 f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s) 601 602 aux := &XcoffAuxCSect64{ 603 Xsmclas: XMC_PR, 604 Xsmtyp: XTY_SD | 5<<3, // align = 5 605 Xauxtype: _AUX_CSECT, 606 } 607 f.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, aux) 608 609 } 610 611 // Update values for the previous package. 612 // - Svalue of the C_FILE symbol: if it is the last one, this Svalue must be -1 613 // - Xsclen of the csect symbol. 614 func (f *xcoffFile) updatePreviousFile(ctxt *Link, last bool) { 615 // first file 616 if currSymSrcFile.fileSymNb == 0 { 617 return 618 } 619 620 prevOff := f.symtabOffset + int64(currSymSrcFile.fileSymNb*SYMESZ) 621 currOff := ctxt.Out.Offset() 622 623 // Update C_FILE 624 ctxt.Out.SeekSet(prevOff) 625 if last { 626 ctxt.Out.Write64(0xFFFFFFFFFFFFFFFF) 627 } else { 628 ctxt.Out.Write64(uint64(f.symbolCount)) 629 } 630 631 // update csect scnlen in this auxiliary entry 632 prevOff = f.symtabOffset + int64((currSymSrcFile.csectSymNb+1)*SYMESZ) 633 ctxt.Out.SeekSet(prevOff) 634 ctxt.Out.Write32(uint32(currSymSrcFile.csectSize & 0xFFFFFFFF)) 635 prevOff += 12 636 ctxt.Out.SeekSet(prevOff) 637 ctxt.Out.Write32(uint32(currSymSrcFile.csectSize >> 32)) 638 639 ctxt.Out.SeekSet(currOff) 640 641 } 642 643 // Write symbol representing a .text function. 644 // The symbol table is split with C_FILE corresponding to each package 645 // and not to each source file as it should be. 646 func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []interface{} { 647 // New XCOFF symbols which will be written. 648 syms := []interface{}{} 649 650 // Check if a new file is detected. 651 if x.File == "" { // Undefined global symbol 652 // If this happens, the algorithme must be redone. 653 if currSymSrcFile.name != "" { 654 Exitf("undefined global symbol found inside another file") 655 } 656 } else { 657 // Current file has changed. New C_FILE, C_DWARF, etc must be generated. 658 if currSymSrcFile.name != x.File { 659 // update previous file values 660 xfile.updatePreviousFile(ctxt, false) 661 currSymSrcFile.name = x.File 662 currSymSrcFile.fileSymNb = f.symbolCount 663 f.writeSymbolNewFile(ctxt, x.File, uint64(x.Value), x.Sect.Extnum) 664 } 665 } 666 667 s := &XcoffSymEnt64{ 668 Nsclass: C_EXT, 669 Noffset: uint32(xfile.stringTable.add(x.Name)), 670 Nvalue: uint64(x.Value), 671 Nscnum: x.Sect.Extnum, 672 Ntype: SYM_TYPE_FUNC, 673 Nnumaux: 2, 674 } 675 676 if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() { 677 s.Nsclass = C_HIDEXT 678 } 679 680 syms = append(syms, s) 681 682 // Update current csect size 683 currSymSrcFile.csectSize += x.Size 684 685 // create auxiliary entries 686 a2 := &XcoffAuxFcn64{ 687 Xfsize: uint32(x.Size), 688 Xlnnoptr: 0, // TODO 689 Xendndx: xfile.symbolCount + 3, // this symbol + 2 aux entries 690 Xauxtype: _AUX_FCN, 691 } 692 syms = append(syms, a2) 693 694 a4 := &XcoffAuxCSect64{ 695 Xscnlenlo: uint32(currSymSrcFile.csectSymNb & 0xFFFFFFFF), 696 Xscnlenhi: uint32(currSymSrcFile.csectSymNb >> 32), 697 Xsmclas: XMC_PR, // Program Code 698 Xsmtyp: XTY_LD, // label definition (based on C) 699 Xauxtype: _AUX_CSECT, 700 } 701 syms = append(syms, a4) 702 return syms 703 } 704 705 // put function used by genasmsym to write symbol table 706 func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64, go_ *sym.Symbol) { 707 708 // All XCOFF symbols generated by this GO symbols 709 // Can be a symbol entry or a auxiliary entry 710 syms := []interface{}{} 711 712 switch t { 713 default: 714 return 715 716 case TextSym: 717 if x.FuncInfo != nil { 718 // Function within a file 719 syms = xfile.writeSymbolFunc(ctxt, x) 720 } else { 721 // Only runtime.text and runtime.etext come through this way 722 if x.Name != "runtime.text" && x.Name != "runtime.etext" && x.Name != "go.buildid" { 723 Exitf("putaixsym: unknown text symbol %s", x.Name) 724 } 725 s := &XcoffSymEnt64{ 726 Nsclass: C_HIDEXT, 727 Noffset: uint32(xfile.stringTable.add(str)), 728 Nvalue: uint64(x.Value), 729 Nscnum: x.Sect.Extnum, 730 Ntype: SYM_TYPE_FUNC, 731 Nnumaux: 1, 732 } 733 syms = append(syms, s) 734 735 size := uint64(x.Size) 736 a4 := &XcoffAuxCSect64{ 737 Xauxtype: _AUX_CSECT, 738 Xscnlenlo: uint32(size & 0xFFFFFFFF), 739 Xscnlenhi: uint32(size >> 32), 740 Xsmclas: XMC_PR, 741 Xsmtyp: XTY_SD, 742 } 743 syms = append(syms, a4) 744 745 } 746 747 case DataSym, BSSSym: 748 s := &XcoffSymEnt64{ 749 Nsclass: C_EXT, 750 Noffset: uint32(xfile.stringTable.add(str)), 751 Nvalue: uint64(x.Value), 752 Nscnum: x.Sect.Extnum, 753 Nnumaux: 1, 754 } 755 756 if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() { 757 // There is more symbols in the case of a global data 758 // which are related to the assembly generated 759 // to access such symbols. 760 // But as Golang as its own way to check if a symbol is 761 // global or local (the capital letter), we don't need to 762 // implement them yet. 763 s.Nsclass = C_HIDEXT 764 } 765 766 syms = append(syms, s) 767 768 // Create auxiliary entry 769 770 // Normally, size should be the size of csect containing all 771 // the data and bss symbols of one file/package. 772 // However, it's easier to just have a csect for each symbol. 773 // It might change 774 size := uint64(x.Size) 775 a4 := &XcoffAuxCSect64{ 776 Xauxtype: _AUX_CSECT, 777 Xscnlenlo: uint32(size & 0xFFFFFFFF), 778 Xscnlenhi: uint32(size >> 32), 779 } 780 // Read only data 781 if x.Type >= sym.STYPE && x.Type <= sym.SPCLNTAB { 782 a4.Xsmclas = XMC_RO 783 } else { 784 a4.Xsmclas = XMC_RW 785 } 786 if t == DataSym { 787 a4.Xsmtyp |= XTY_SD 788 } else { 789 a4.Xsmtyp |= XTY_CM 790 } 791 792 syms = append(syms, a4) 793 794 } 795 for _, s := range syms { 796 xfile.writeSymbol(ctxt.Out, ctxt.Arch.ByteOrder, s) 797 } 798 } 799 800 // Generate XCOFF Symbol table and XCOFF String table 801 func Asmaixsym(ctxt *Link) { 802 // write symbol table 803 xfile.symtabOffset = ctxt.Out.Offset() 804 genasmsym(ctxt, putaixsym) 805 806 // update last file Svalue 807 xfile.updatePreviousFile(ctxt, true) 808 809 // write string table 810 xfile.stringTable.write(ctxt.Out) 811 } 812 813 // xcoffadddynimpsym adds a dynamic symbol to a XCOFF file 814 func xcoffadddynimpsym(ctxt *Link, s *sym.Symbol) { 815 xfile.adddynimpsym(ctxt, s) 816 } 817 818 // Add a new imported symbol and a new library if needed. 819 // Currently, dynamic symbols are considered as .data symbols which will receive 820 // their value by the loader. Their relocation is created during the creation 821 // of the .loader section, because it needs its symbol index. 822 // However, there is no writing protection on those symbols and 823 // it might need to be added. 824 // TODO(aix): Add writing protection. 825 // TODO(aix): Handles dynamic symbols without library. 826 func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) { 827 // Check that library name is given. 828 // Pattern is already checked when compiling. 829 if s.Dynimplib() == "" { 830 Errorf(s, "imported symbol must have a given library") 831 } 832 833 for _, sf := range f.dynSymbols { 834 if sf == s { 835 return 836 } 837 } 838 839 f.dynSymbols = append(f.dynSymbols, s) 840 s.Type = sym.SXCOFFTOC 841 // Function descriptor value 842 s.AddUint64(ctxt.Arch, 0) 843 844 if _, ok := f.dynLibraries[s.Dynimplib()]; !ok { 845 f.dynLibraries[s.Dynimplib()] = len(f.dynLibraries) 846 } 847 } 848 849 // Add a relocation to .loader relocation section 850 func xcoffaddloaderreloc(ctxt *Link, s *sym.Symbol, r *sym.Reloc) { 851 if s.Type <= sym.SPCLNTAB && r.Sym.Type >= sym.SELFSECT && r.Sym.Type <= sym.SXREF { 852 Errorf(s, "cannot have a relocation in a text section with a data symbol: %s ", r.Sym.Name) 853 } 854 855 ldr := &XcoffLdRel64{ 856 Lvaddr: uint64(s.Value + int64(r.Off)), 857 Lrsecnm: s.Sect.Extnum, 858 } 859 860 switch r.Type { 861 case objabi.R_ADDR: 862 // Relocation of a .data symbol 863 ldr.Lrtype = 0x3F<<8 + XCOFF_R_POS 864 ldr.Lsymndx = 1 // .data 865 default: 866 Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", r.Sym.Name, r.Type.String()) 867 } 868 869 xfile.loaderReloc = append(xfile.loaderReloc, ldr) 870 871 } 872 873 func (ctxt *Link) doxcoff() { 874 // Initial map used to store compilation unit size for each DWARF section (see dwarf.go). 875 dwsectCUSize = make(map[string]uint64) 876 877 // TOC 878 toc := ctxt.Syms.Lookup("TOC", 0) 879 toc.Type = sym.SXCOFFTOC 880 toc.Attr |= sym.AttrReachable 881 } 882 883 // Loader section 884 // Currently, this section is created from scratch when assembling the XCOFF file 885 // according to information retrieved in xfile object. 886 887 // Create loader section and returns its size 888 func Loaderblk(ctxt *Link, off uint64) uint64 { 889 xfile.writeLdrScn(ctxt, off) 890 return loaderSize 891 } 892 893 func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) { 894 var symtab []*XcoffLdSym64 895 var strtab []*XcoffLdStr64 896 var importtab []*XcoffLdImportFile64 897 var reloctab []*XcoffLdRel64 898 var dynimpreloc []*XcoffLdRel64 899 900 // As the string table is updated in any loader subsection, 901 // its length must be computed at the same time. 902 stlen := uint32(0) 903 904 // Loader Header 905 hdr := &XcoffLdHdr64{ 906 Lversion: 2, 907 Lsymoff: LDHDRSZ_64, 908 } 909 910 /* Symbol table */ 911 // Entry point symbol 912 ep := ctxt.Syms.ROLookup(*flagEntrySymbol, 0) 913 if !ep.Attr.Reachable() { 914 Exitf("wrong entry point") 915 } 916 lds := &XcoffLdSym64{ 917 Lvalue: uint64(ep.Value), 918 Loffset: uint32(stlen + 2), // +2 because it must have the first byte of the symbol not its size field 919 Lscnum: ep.Sect.Extnum, 920 Lsmtype: XTY_ENT | XTY_SD, 921 Lsmclas: XMC_DS, 922 Lifile: 0, 923 Lparm: 0, 924 } 925 ldstr := &XcoffLdStr64{ 926 size: uint16(len(ep.String()) + 1), // + null terminator 927 name: ep.String(), 928 } 929 stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size 930 symtab = append(symtab, lds) 931 strtab = append(strtab, ldstr) 932 933 nbldsym := int32(4) 934 935 // dynamic import 936 for _, s := range f.dynSymbols { 937 lds = &XcoffLdSym64{ 938 Loffset: uint32(stlen + 2), 939 Lsmtype: XTY_IMP, 940 Lsmclas: XMC_DS, 941 Lifile: int32(f.dynLibraries[s.Dynimplib()] + 1), 942 } 943 ldstr := &XcoffLdStr64{ 944 size: uint16(len(s.Extname()) + 1), // + null terminator 945 name: s.Extname(), 946 } 947 stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size 948 symtab = append(symtab, lds) 949 strtab = append(strtab, ldstr) 950 951 // Create relocation entry at the same moment to get symndx 952 ldr := &XcoffLdRel64{ 953 Lvaddr: uint64(s.Value), 954 Lrtype: 0x3F00, 955 Lrsecnm: s.Sect.Extnum, 956 Lsymndx: int32(nbldsym), 957 } 958 dynimpreloc = append(dynimpreloc, ldr) 959 nbldsym++ 960 961 } 962 963 hdr.Lnsyms = int32(len(symtab)) 964 hdr.Lrldoff = hdr.Lsymoff + uint64(24*hdr.Lnsyms) // 24 = sizeof one symbol 965 off := hdr.Lrldoff // current offset is the same of reloc offset 966 967 /* Reloc */ 968 ldr := &XcoffLdRel64{ 969 Lvaddr: uint64(ep.Value), 970 Lrtype: 0x3F00, 971 Lrsecnm: ep.Sect.Extnum, 972 Lsymndx: 0, 973 } 974 off += 16 975 reloctab = append(reloctab, ldr) 976 977 off += uint64(16 * len(f.loaderReloc)) 978 reloctab = append(reloctab, (f.loaderReloc)...) 979 980 off += uint64(16 * len(dynimpreloc)) 981 reloctab = append(reloctab, dynimpreloc...) 982 983 hdr.Lnreloc = int32(len(reloctab)) 984 hdr.Limpoff = off 985 986 /* Import */ 987 // Default import: /usr/lib:/lib 988 ldimpf := &XcoffLdImportFile64{ 989 Limpidpath: "/usr/lib:/lib", 990 } 991 off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter 992 importtab = append(importtab, ldimpf) 993 994 // The map created by adddynimpsym associates the name to a number 995 // This number represents the librairie index (- 1) in this import files section 996 // Therefore, they must be sorted before being put inside the section 997 libsOrdered := make([]string, len(f.dynLibraries)) 998 for key, val := range f.dynLibraries { 999 if libsOrdered[val] != "" { 1000 continue 1001 } 1002 libsOrdered[val] = key 1003 } 1004 1005 for _, lib := range libsOrdered { 1006 // lib string is defined as base.a/mem.o or path/base.a/mem.o 1007 n := strings.Split(lib, "/") 1008 path := "" 1009 base := n[len(n)-2] 1010 mem := n[len(n)-1] 1011 if len(n) > 2 { 1012 path = lib[:len(lib)-len(base)-len(mem)-2] 1013 1014 } 1015 ldimpf = &XcoffLdImportFile64{ 1016 Limpidpath: path, 1017 Limpidbase: base, 1018 Limpidmem: mem, 1019 } 1020 off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter 1021 importtab = append(importtab, ldimpf) 1022 } 1023 1024 hdr.Lnimpid = int32(len(importtab)) 1025 hdr.Listlen = uint32(off - hdr.Limpoff) 1026 hdr.Lstoff = off 1027 hdr.Lstlen = stlen 1028 1029 /* Writing */ 1030 ctxt.Out.SeekSet(int64(globalOff)) 1031 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, hdr) 1032 1033 for _, s := range symtab { 1034 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s) 1035 1036 } 1037 for _, r := range reloctab { 1038 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, r) 1039 } 1040 for _, f := range importtab { 1041 ctxt.Out.WriteString(f.Limpidpath) 1042 ctxt.Out.Write8(0) 1043 ctxt.Out.WriteString(f.Limpidbase) 1044 ctxt.Out.Write8(0) 1045 ctxt.Out.WriteString(f.Limpidmem) 1046 ctxt.Out.Write8(0) 1047 } 1048 for _, s := range strtab { 1049 ctxt.Out.Write16(s.size) 1050 ctxt.Out.WriteString(s.name) 1051 ctxt.Out.Write8(0) // null terminator 1052 } 1053 1054 loaderOff = globalOff 1055 loaderSize = off + uint64(stlen) 1056 ctxt.Out.Flush() 1057 1058 /* again for printing */ 1059 if !*flagA { 1060 return 1061 } 1062 1063 ctxt.Logf("\n.loader section") 1064 // write in buf 1065 var buf bytes.Buffer 1066 1067 binary.Write(&buf, ctxt.Arch.ByteOrder, hdr) 1068 for _, s := range symtab { 1069 binary.Write(&buf, ctxt.Arch.ByteOrder, s) 1070 1071 } 1072 for _, f := range importtab { 1073 buf.WriteString(f.Limpidpath) 1074 buf.WriteByte(0) 1075 buf.WriteString(f.Limpidbase) 1076 buf.WriteByte(0) 1077 buf.WriteString(f.Limpidmem) 1078 buf.WriteByte(0) 1079 } 1080 for _, s := range strtab { 1081 binary.Write(&buf, ctxt.Arch.ByteOrder, s.size) 1082 buf.WriteString(s.name) 1083 buf.WriteByte(0) // null terminator 1084 } 1085 1086 // Log buffer 1087 ctxt.Logf("\n\t%.8x|", globalOff) 1088 for i, b := range buf.Bytes() { 1089 if i > 0 && i%16 == 0 { 1090 ctxt.Logf("\n\t%.8x|", uint64(globalOff)+uint64(i)) 1091 } 1092 ctxt.Logf(" %.2x", b) 1093 } 1094 ctxt.Logf("\n") 1095 1096 } 1097 1098 // XCOFF assembling and writing file 1099 1100 func (f *xcoffFile) writeFileHeader(ctxt *Link) { 1101 // File header 1102 f.xfhdr.Fmagic = U64_TOCMAGIC 1103 f.xfhdr.Fnscns = uint16(len(f.sections)) 1104 f.xfhdr.Ftimedat = 0 1105 1106 if !*FlagS { 1107 f.xfhdr.Fsymptr = uint64(f.symtabOffset) 1108 f.xfhdr.Fnsyms = int32(f.symbolCount) 1109 } 1110 1111 if ctxt.BuildMode == BuildModeExe { 1112 f.xfhdr.Fopthdr = AOUTHSZ_EXEC64 1113 f.xfhdr.Fflags = F_EXEC 1114 1115 // auxiliary header 1116 f.xahdr.Ovstamp = 1 // based on dump -o 1117 f.xahdr.Omagic = 0x10b 1118 copy(f.xahdr.Omodtype[:], "1L") 1119 f.xahdr.Oentry = uint64(Entryvalue(ctxt)) 1120 f.xahdr.Otoc = uint64(ctxt.Syms.ROLookup("TOC", 0).Value) 1121 1122 // Based on dump -o 1123 f.xahdr.Oalgntext = 0x5 1124 f.xahdr.Oalgndata = 0x5 1125 1126 binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr) 1127 binary.Write(ctxt.Out, binary.BigEndian, &f.xahdr) 1128 } else { 1129 f.xfhdr.Fopthdr = 0 1130 binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr) 1131 } 1132 1133 } 1134 1135 func xcoffwrite(ctxt *Link) { 1136 ctxt.Out.SeekSet(0) 1137 1138 xfile.writeFileHeader(ctxt) 1139 1140 for _, sect := range xfile.sections { 1141 sect.write(ctxt) 1142 } 1143 } 1144 1145 // Generate XCOFF assembly file 1146 func Asmbxcoff(ctxt *Link) { 1147 // initial offset for sections 1148 if ctxt.BuildMode == BuildModeExe { 1149 // search entry section number 1150 eaddr := uint64(Entryvalue(ctxt)) 1151 for _, sect := range append(Segtext.Sections, Segdata.Sections...) { 1152 if eaddr-sect.Vaddr <= sect.Length { 1153 xfile.xahdr.Osnentry = int16(sect.Extnum) 1154 } 1155 } 1156 1157 // check 1158 if xfile.xahdr.Osnentry == 0 { 1159 Exitf("internal error: Section number for entry point (addr = 0x%x) not found", eaddr) 1160 } 1161 1162 } 1163 1164 // add text sections 1165 for _, sect := range Segtext.Sections { 1166 // ctxt.Logf(".text: %s \n", sect.Name) 1167 s := xfile.addSection(sect) 1168 s.Sflags = STYP_TEXT 1169 1170 // use sect.Name because of convertion inside scnhdr 1171 if sect.Name == ".text" { 1172 xfile.xahdr.Otextstart = s.Spaddr 1173 xfile.xahdr.Otsize = s.Ssize 1174 xfile.xahdr.Osntext = sect.Extnum 1175 } 1176 } 1177 1178 // add data sections 1179 var ( 1180 snoptrdata, 1181 sdata, 1182 sbss, 1183 snoptrbss *sym.Section 1184 ) 1185 for _, sect := range Segdata.Sections { 1186 if sect.Name == ".noptrdata" { 1187 snoptrdata = sect 1188 } 1189 if sect.Name == ".noptrbss" { 1190 snoptrbss = sect 1191 } 1192 if sect.Name == ".data" { 1193 sdata = sect 1194 } 1195 if sect.Name == ".bss" { 1196 sbss = sect 1197 } 1198 } 1199 1200 // On AIX, there must be only one data and one bss section. 1201 // Therefore, their noptr section is merged within them. 1202 // The length of the new section must be recomputed to handle defautl gap 1203 // between GO sections as AIX doesn't allow it. 1204 1205 // Merge .noptrdata inside .data 1206 sdata.Vaddr = snoptrdata.Vaddr 1207 sdata.Length = sbss.Vaddr - sdata.Vaddr 1208 s := xfile.addSection(sdata) 1209 s.Sflags = STYP_DATA 1210 xfile.xahdr.Odatastart = s.Spaddr 1211 xfile.xahdr.Odsize = s.Ssize 1212 xfile.xahdr.Osndata = sdata.Extnum 1213 1214 // Merge .noptrbss inside .bss 1215 sbss.Length = snoptrbss.Vaddr + snoptrbss.Length - sbss.Vaddr 1216 s = xfile.addSection(sbss) 1217 s.Sflags = STYP_BSS 1218 xfile.xahdr.Obsize = s.Ssize 1219 xfile.xahdr.Osnbss = sbss.Extnum 1220 s.Sscnptr = 0 1221 1222 // add dwarf section 1223 for _, sect := range Segdwarf.Sections { 1224 xfile.addDwarfSection(sect) 1225 } 1226 1227 // Loader section must be add at the end because of sect.Extnum 1228 // in others sections 1229 xfile.addLoaderSection(loaderSize, loaderOff) 1230 1231 xcoffwrite(ctxt) 1232 }