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