github.com/bir3/gocompiler@v0.3.205/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 a 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 *FlagTextAddr != -1 { 548 Errorf(nil, "-T not available on AIX") 549 } 550 *FlagTextAddr = XCOFFTEXTBASE + int64(HEADR) 551 if *FlagRound != -1 { 552 Errorf(nil, "-R not available on AIX") 553 } 554 *FlagRound = int(XCOFFSECTALIGN) 555 556 } 557 558 // SYMBOL TABLE 559 560 // type records C_FILE information needed for genasmsym in XCOFF. 561 type xcoffSymSrcFile struct { 562 name string 563 file *XcoffSymEnt64 // Symbol of this C_FILE 564 csectAux *XcoffAuxCSect64 // Symbol for the current .csect 565 csectSymNb uint64 // Symbol number for the current .csect 566 csectVAStart int64 567 csectVAEnd int64 568 } 569 570 var ( 571 currDwscnoff = make(map[string]uint64) // Needed to create C_DWARF symbols 572 currSymSrcFile xcoffSymSrcFile 573 outerSymSize = make(map[string]int64) 574 ) 575 576 // xcoffUpdateOuterSize stores the size of outer symbols in order to have it 577 // in the symbol table. 578 func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) { 579 if size == 0 { 580 return 581 } 582 // TODO: use CarrierSymByType 583 584 ldr := ctxt.loader 585 switch stype { 586 default: 587 Errorf(nil, "unknown XCOFF outer symbol for type %s", stype.String()) 588 case sym.SRODATA, sym.SRODATARELRO, sym.SFUNCTAB, sym.SSTRING: 589 // Nothing to do 590 case sym.STYPERELRO: 591 if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) { 592 // runtime.types size must be removed, as it's a real symbol. 593 tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0)) 594 outerSymSize["typerel.*"] = size - tsize 595 return 596 } 597 fallthrough 598 case sym.STYPE: 599 if !ctxt.DynlinkingGo() { 600 // runtime.types size must be removed, as it's a real symbol. 601 tsize := ldr.SymSize(ldr.Lookup("runtime.types", 0)) 602 outerSymSize["type:*"] = size - tsize 603 } 604 case sym.SGOSTRING: 605 outerSymSize["go:string.*"] = size 606 case sym.SGOFUNC: 607 if !ctxt.DynlinkingGo() { 608 outerSymSize["go:func.*"] = size 609 } 610 case sym.SGOFUNCRELRO: 611 outerSymSize["go:funcrel.*"] = size 612 case sym.SGCBITS: 613 outerSymSize["runtime.gcbits.*"] = size 614 case sym.SPCLNTAB: 615 outerSymSize["runtime.pclntab"] = size 616 } 617 } 618 619 // addSymbol writes a symbol or an auxiliary symbol entry on ctxt.out. 620 func (f *xcoffFile) addSymbol(sym xcoffSym) { 621 f.symtabSym = append(f.symtabSym, sym) 622 f.symbolCount++ 623 } 624 625 // xcoffAlign returns the log base 2 of the symbol's alignment. 626 func xcoffAlign(ldr *loader.Loader, x loader.Sym, t SymbolType) uint8 { 627 align := ldr.SymAlign(x) 628 if align == 0 { 629 if t == TextSym { 630 align = int32(Funcalign) 631 } else { 632 align = symalign(ldr, x) 633 } 634 } 635 return logBase2(int(align)) 636 } 637 638 // logBase2 returns the log in base 2 of a. 639 func logBase2(a int) uint8 { 640 return uint8(bits.Len(uint(a)) - 1) 641 } 642 643 // Write symbols needed when a new file appeared: 644 // - a C_FILE with one auxiliary entry for its name 645 // - C_DWARF symbols to provide debug information 646 // - a C_HIDEXT which will be a csect containing all of its functions 647 // It needs several parameters to create .csect symbols such as its entry point and its section number. 648 // 649 // Currently, a new file is in fact a new package. It seems to be OK, but it might change 650 // in the future. 651 func (f *xcoffFile) writeSymbolNewFile(ctxt *Link, name string, firstEntry uint64, extnum int16) { 652 ldr := ctxt.loader 653 /* C_FILE */ 654 s := &XcoffSymEnt64{ 655 Noffset: uint32(f.stringTable.add(".file")), 656 Nsclass: C_FILE, 657 Nscnum: N_DEBUG, 658 Ntype: 0, // Go isn't inside predefined language. 659 Nnumaux: 1, 660 } 661 f.addSymbol(s) 662 currSymSrcFile.file = s 663 664 // Auxiliary entry for file name. 665 auxf := &XcoffAuxFile64{ 666 Xoffset: uint32(f.stringTable.add(name)), 667 Xftype: XFT_FN, 668 Xauxtype: _AUX_FILE, 669 } 670 f.addSymbol(auxf) 671 672 /* Dwarf */ 673 for _, sect := range Segdwarf.Sections { 674 var dwsize uint64 675 if ctxt.LinkMode == LinkInternal { 676 // Find the size of this corresponding package DWARF compilation unit. 677 // This size is set during DWARF generation (see dwarf.go). 678 dwsize = getDwsectCUSize(sect.Name, name) 679 // .debug_abbrev is common to all packages and not found with the previous function 680 if sect.Name == ".debug_abbrev" { 681 dwsize = uint64(ldr.SymSize(loader.Sym(sect.Sym))) 682 683 } 684 } else { 685 // There is only one .FILE with external linking. 686 dwsize = sect.Length 687 } 688 689 // get XCOFF name 690 name, _ := xcoffGetDwarfSubtype(sect.Name) 691 s := &XcoffSymEnt64{ 692 Nvalue: currDwscnoff[sect.Name], 693 Noffset: uint32(f.stringTable.add(name)), 694 Nsclass: C_DWARF, 695 Nscnum: f.getXCOFFscnum(sect), 696 Nnumaux: 1, 697 } 698 699 if currSymSrcFile.csectAux == nil { 700 // Dwarf relocations need the symbol number of .dw* symbols. 701 // It doesn't need to know it for each package, one is enough. 702 // currSymSrcFile.csectAux == nil means first package. 703 ldr.SetSymDynid(loader.Sym(sect.Sym), int32(f.symbolCount)) 704 705 if sect.Name == ".debug_frame" && ctxt.LinkMode != LinkExternal { 706 // CIE size must be added to the first package. 707 dwsize += 48 708 } 709 } 710 711 f.addSymbol(s) 712 713 // update the DWARF section offset in this file 714 if sect.Name != ".debug_abbrev" { 715 currDwscnoff[sect.Name] += dwsize 716 } 717 718 // Auxiliary dwarf section 719 auxd := &XcoffAuxDWARF64{ 720 Xscnlen: dwsize, 721 Xauxtype: _AUX_SECT, 722 } 723 724 f.addSymbol(auxd) 725 } 726 727 /* .csect */ 728 // Check if extnum is in text. 729 // This is temporary and only here to check if this algorithm is correct. 730 if extnum != 1 { 731 Exitf("XCOFF symtab: A new file was detected with its first symbol not in .text") 732 } 733 734 currSymSrcFile.csectSymNb = uint64(f.symbolCount) 735 736 // No offset because no name 737 s = &XcoffSymEnt64{ 738 Nvalue: firstEntry, 739 Nscnum: extnum, 740 Nsclass: C_HIDEXT, 741 Ntype: 0, // check visibility ? 742 Nnumaux: 1, 743 } 744 f.addSymbol(s) 745 746 aux := &XcoffAuxCSect64{ 747 Xsmclas: XMC_PR, 748 Xsmtyp: XTY_SD | logBase2(Funcalign)<<3, 749 Xauxtype: _AUX_CSECT, 750 } 751 f.addSymbol(aux) 752 753 currSymSrcFile.csectAux = aux 754 currSymSrcFile.csectVAStart = int64(firstEntry) 755 currSymSrcFile.csectVAEnd = int64(firstEntry) 756 } 757 758 // Update values for the previous package. 759 // - Svalue of the C_FILE symbol: if it is the last one, this Svalue must be -1 760 // - Xsclen of the csect symbol. 761 func (f *xcoffFile) updatePreviousFile(ctxt *Link, last bool) { 762 // first file 763 if currSymSrcFile.file == nil { 764 return 765 } 766 767 // Update C_FILE 768 cfile := currSymSrcFile.file 769 if last { 770 cfile.Nvalue = 0xFFFFFFFFFFFFFFFF 771 } else { 772 cfile.Nvalue = uint64(f.symbolCount) 773 } 774 775 // update csect scnlen in this auxiliary entry 776 aux := currSymSrcFile.csectAux 777 csectSize := currSymSrcFile.csectVAEnd - currSymSrcFile.csectVAStart 778 aux.Xscnlenlo = uint32(csectSize & 0xFFFFFFFF) 779 aux.Xscnlenhi = uint32(csectSize >> 32) 780 } 781 782 // Write symbol representing a .text function. 783 // The symbol table is split with C_FILE corresponding to each package 784 // and not to each source file as it should be. 785 func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x loader.Sym) []xcoffSym { 786 // New XCOFF symbols which will be written. 787 syms := []xcoffSym{} 788 789 // Check if a new file is detected. 790 ldr := ctxt.loader 791 name := ldr.SymName(x) 792 if strings.Contains(name, "-tramp") || strings.HasPrefix(name, "runtime.text.") { 793 // Trampoline don't have a FILE so there are considered 794 // in the current file. 795 // Same goes for runtime.text.X symbols. 796 } else if ldr.SymPkg(x) == "" { // Undefined global symbol 797 // If this happens, the algorithm must be redone. 798 if currSymSrcFile.name != "" { 799 Exitf("undefined global symbol found inside another file") 800 } 801 } else { 802 // Current file has changed. New C_FILE, C_DWARF, etc must be generated. 803 if currSymSrcFile.name != ldr.SymPkg(x) { 804 if ctxt.LinkMode == LinkInternal { 805 // update previous file values 806 xfile.updatePreviousFile(ctxt, false) 807 currSymSrcFile.name = ldr.SymPkg(x) 808 f.writeSymbolNewFile(ctxt, ldr.SymPkg(x), uint64(ldr.SymValue(x)), xfile.getXCOFFscnum(ldr.SymSect(x))) 809 } else { 810 // With external linking, ld will crash if there is several 811 // .FILE and DWARF debugging enable, somewhere during 812 // the relocation phase. 813 // Therefore, all packages are merged under a fake .FILE 814 // "go_functions". 815 // TODO(aix); remove once ld has been fixed or the triggering 816 // relocation has been found and fixed. 817 if currSymSrcFile.name == "" { 818 currSymSrcFile.name = ldr.SymPkg(x) 819 f.writeSymbolNewFile(ctxt, "go_functions", uint64(ldr.SymValue(x)), xfile.getXCOFFscnum(ldr.SymSect(x))) 820 } 821 } 822 823 } 824 } 825 826 name = ldr.SymExtname(x) 827 name = mangleABIName(ctxt, ldr, x, name) 828 829 s := &XcoffSymEnt64{ 830 Nsclass: C_EXT, 831 Noffset: uint32(xfile.stringTable.add(name)), 832 Nvalue: uint64(ldr.SymValue(x)), 833 Nscnum: f.getXCOFFscnum(ldr.SymSect(x)), 834 Ntype: SYM_TYPE_FUNC, 835 Nnumaux: 2, 836 } 837 838 if ldr.IsFileLocal(x) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) { 839 s.Nsclass = C_HIDEXT 840 } 841 842 ldr.SetSymDynid(x, int32(xfile.symbolCount)) 843 syms = append(syms, s) 844 845 // Keep track of the section size by tracking the VA range. Individual 846 // alignment differences may introduce a few extra bytes of padding 847 // which are not fully accounted for by ldr.SymSize(x). 848 sv := ldr.SymValue(x) + ldr.SymSize(x) 849 if currSymSrcFile.csectVAEnd < sv { 850 currSymSrcFile.csectVAEnd = sv 851 } 852 853 // create auxiliary entries 854 a2 := &XcoffAuxFcn64{ 855 Xfsize: uint32(ldr.SymSize(x)), 856 Xlnnoptr: 0, // TODO 857 Xendndx: xfile.symbolCount + 3, // this symbol + 2 aux entries 858 Xauxtype: _AUX_FCN, 859 } 860 syms = append(syms, a2) 861 862 a4 := &XcoffAuxCSect64{ 863 Xscnlenlo: uint32(currSymSrcFile.csectSymNb & 0xFFFFFFFF), 864 Xscnlenhi: uint32(currSymSrcFile.csectSymNb >> 32), 865 Xsmclas: XMC_PR, // Program Code 866 Xsmtyp: XTY_LD, // label definition (based on C) 867 Xauxtype: _AUX_CSECT, 868 } 869 a4.Xsmtyp |= uint8(xcoffAlign(ldr, x, TextSym) << 3) 870 871 syms = append(syms, a4) 872 return syms 873 } 874 875 // put function used by genasmsym to write symbol table. 876 func putaixsym(ctxt *Link, x loader.Sym, t SymbolType) { 877 // All XCOFF symbols generated by this GO symbols 878 // Can be a symbol entry or a auxiliary entry 879 syms := []xcoffSym{} 880 881 ldr := ctxt.loader 882 name := ldr.SymName(x) 883 if t == UndefinedSym { 884 name = ldr.SymExtname(x) 885 } 886 887 switch t { 888 default: 889 return 890 891 case TextSym: 892 if ldr.SymPkg(x) != "" || strings.Contains(name, "-tramp") || strings.HasPrefix(name, "runtime.text.") { 893 // Function within a file 894 syms = xfile.writeSymbolFunc(ctxt, x) 895 } else { 896 // Only runtime.text and runtime.etext come through this way 897 if name != "runtime.text" && name != "runtime.etext" && name != "go:buildid" { 898 Exitf("putaixsym: unknown text symbol %s", name) 899 } 900 s := &XcoffSymEnt64{ 901 Nsclass: C_HIDEXT, 902 Noffset: uint32(xfile.stringTable.add(name)), 903 Nvalue: uint64(ldr.SymValue(x)), 904 Nscnum: xfile.getXCOFFscnum(ldr.SymSect(x)), 905 Ntype: SYM_TYPE_FUNC, 906 Nnumaux: 1, 907 } 908 ldr.SetSymDynid(x, int32(xfile.symbolCount)) 909 syms = append(syms, s) 910 911 size := uint64(ldr.SymSize(x)) 912 a4 := &XcoffAuxCSect64{ 913 Xauxtype: _AUX_CSECT, 914 Xscnlenlo: uint32(size & 0xFFFFFFFF), 915 Xscnlenhi: uint32(size >> 32), 916 Xsmclas: XMC_PR, 917 Xsmtyp: XTY_SD, 918 } 919 a4.Xsmtyp |= uint8(xcoffAlign(ldr, x, TextSym) << 3) 920 syms = append(syms, a4) 921 } 922 923 case DataSym, BSSSym: 924 s := &XcoffSymEnt64{ 925 Nsclass: C_EXT, 926 Noffset: uint32(xfile.stringTable.add(name)), 927 Nvalue: uint64(ldr.SymValue(x)), 928 Nscnum: xfile.getXCOFFscnum(ldr.SymSect(x)), 929 Nnumaux: 1, 930 } 931 932 if ldr.IsFileLocal(x) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) { 933 // There is more symbols in the case of a global data 934 // which are related to the assembly generated 935 // to access such symbols. 936 // But as Golang as its own way to check if a symbol is 937 // global or local (the capital letter), we don't need to 938 // implement them yet. 939 s.Nsclass = C_HIDEXT 940 } 941 942 ldr.SetSymDynid(x, int32(xfile.symbolCount)) 943 syms = append(syms, s) 944 945 // Create auxiliary entry 946 947 // Normally, size should be the size of csect containing all 948 // the data and bss symbols of one file/package. 949 // However, it's easier to just have a csect for each symbol. 950 // It might change 951 size := uint64(ldr.SymSize(x)) 952 a4 := &XcoffAuxCSect64{ 953 Xauxtype: _AUX_CSECT, 954 Xscnlenlo: uint32(size & 0xFFFFFFFF), 955 Xscnlenhi: uint32(size >> 32), 956 } 957 958 if ty := ldr.SymType(x); ty >= sym.STYPE && ty <= sym.SPCLNTAB { 959 if ctxt.IsExternal() && strings.HasPrefix(ldr.SymSect(x).Name, ".data.rel.ro") { 960 // During external linking, read-only datas with relocation 961 // must be in .data. 962 a4.Xsmclas = XMC_RW 963 } else { 964 // Read only data 965 a4.Xsmclas = XMC_RO 966 } 967 } else if /*ty == sym.SDATA &&*/ strings.HasPrefix(ldr.SymName(x), "TOC.") && ctxt.IsExternal() { 968 a4.Xsmclas = XMC_TC 969 } else if ldr.SymName(x) == "TOC" { 970 a4.Xsmclas = XMC_TC0 971 } else { 972 a4.Xsmclas = XMC_RW 973 } 974 if t == DataSym { 975 a4.Xsmtyp |= XTY_SD 976 } else { 977 a4.Xsmtyp |= XTY_CM 978 } 979 980 a4.Xsmtyp |= uint8(xcoffAlign(ldr, x, t) << 3) 981 982 syms = append(syms, a4) 983 984 case UndefinedSym: 985 if ty := ldr.SymType(x); ty != sym.SDYNIMPORT && ty != sym.SHOSTOBJ && ty != sym.SUNDEFEXT { 986 return 987 } 988 s := &XcoffSymEnt64{ 989 Nsclass: C_EXT, 990 Noffset: uint32(xfile.stringTable.add(name)), 991 Nnumaux: 1, 992 } 993 ldr.SetSymDynid(x, int32(xfile.symbolCount)) 994 syms = append(syms, s) 995 996 a4 := &XcoffAuxCSect64{ 997 Xauxtype: _AUX_CSECT, 998 Xsmclas: XMC_DS, 999 Xsmtyp: XTY_ER | XTY_IMP, 1000 } 1001 1002 if ldr.SymName(x) == "__n_pthreads" { 1003 // Currently, all imported symbols made by cgo_import_dynamic are 1004 // syscall functions, except __n_pthreads which is a variable. 1005 // TODO(aix): Find a way to detect variables imported by cgo. 1006 a4.Xsmclas = XMC_RW 1007 } 1008 1009 syms = append(syms, a4) 1010 1011 case TLSSym: 1012 s := &XcoffSymEnt64{ 1013 Nsclass: C_EXT, 1014 Noffset: uint32(xfile.stringTable.add(name)), 1015 Nscnum: xfile.getXCOFFscnum(ldr.SymSect(x)), 1016 Nvalue: uint64(ldr.SymValue(x)), 1017 Nnumaux: 1, 1018 } 1019 1020 ldr.SetSymDynid(x, int32(xfile.symbolCount)) 1021 syms = append(syms, s) 1022 1023 size := uint64(ldr.SymSize(x)) 1024 a4 := &XcoffAuxCSect64{ 1025 Xauxtype: _AUX_CSECT, 1026 Xsmclas: XMC_UL, 1027 Xsmtyp: XTY_CM, 1028 Xscnlenlo: uint32(size & 0xFFFFFFFF), 1029 Xscnlenhi: uint32(size >> 32), 1030 } 1031 1032 syms = append(syms, a4) 1033 } 1034 1035 for _, s := range syms { 1036 xfile.addSymbol(s) 1037 } 1038 } 1039 1040 // Generate XCOFF Symbol table. 1041 // It will be written in out file in Asmbxcoff, because it must be 1042 // at the very end, especially after relocation sections which needs symbols' index. 1043 func (f *xcoffFile) asmaixsym(ctxt *Link) { 1044 ldr := ctxt.loader 1045 // Get correct size for symbols wrapping others symbols like go.string.* 1046 // sym.Size can be used directly as the symbols have already been written. 1047 for name, size := range outerSymSize { 1048 sym := ldr.Lookup(name, 0) 1049 if sym == 0 { 1050 Errorf(nil, "unknown outer symbol with name %s", name) 1051 } else { 1052 s := ldr.MakeSymbolUpdater(sym) 1053 s.SetSize(size) 1054 } 1055 } 1056 1057 // These symbols won't show up in the first loop below because we 1058 // skip sym.STEXT symbols. Normal sym.STEXT symbols are emitted by walking textp. 1059 s := ldr.Lookup("runtime.text", 0) 1060 if ldr.SymType(s) == sym.STEXT { 1061 // We've already included this symbol in ctxt.Textp on AIX with external linker. 1062 // See data.go:/textaddress 1063 if !ctxt.IsExternal() { 1064 putaixsym(ctxt, s, TextSym) 1065 } 1066 } 1067 1068 n := 1 1069 // Generate base addresses for all text sections if there are multiple 1070 for _, sect := range Segtext.Sections[1:] { 1071 if sect.Name != ".text" || ctxt.IsExternal() { 1072 // On AIX, runtime.text.X are symbols already in the symtab. 1073 break 1074 } 1075 s = ldr.Lookup(fmt.Sprintf("runtime.text.%d", n), 0) 1076 if s == 0 { 1077 break 1078 } 1079 if ldr.SymType(s) == sym.STEXT { 1080 putaixsym(ctxt, s, TextSym) 1081 } 1082 n++ 1083 } 1084 1085 s = ldr.Lookup("runtime.etext", 0) 1086 if ldr.SymType(s) == sym.STEXT { 1087 // We've already included this symbol in ctxt.Textp 1088 // on AIX with external linker. 1089 // See data.go:/textaddress 1090 if !ctxt.IsExternal() { 1091 putaixsym(ctxt, s, TextSym) 1092 } 1093 } 1094 1095 shouldBeInSymbolTable := func(s loader.Sym, name string) bool { 1096 if name == ".go.buildinfo" { 1097 // On AIX, .go.buildinfo must be in the symbol table as 1098 // it has relocations. 1099 return true 1100 } 1101 if ldr.AttrNotInSymbolTable(s) { 1102 return false 1103 } 1104 if (name == "" || name[0] == '.') && !ldr.IsFileLocal(s) && name != ".TOC." { 1105 return false 1106 } 1107 return true 1108 } 1109 1110 for s, nsym := loader.Sym(1), loader.Sym(ldr.NSym()); s < nsym; s++ { 1111 if !shouldBeInSymbolTable(s, ldr.SymName(s)) { 1112 continue 1113 } 1114 st := ldr.SymType(s) 1115 switch { 1116 case st == sym.STLSBSS: 1117 if ctxt.IsExternal() { 1118 putaixsym(ctxt, s, TLSSym) 1119 } 1120 1121 case st == sym.SBSS, st == sym.SNOPTRBSS, st == sym.SLIBFUZZER_8BIT_COUNTER, st == sym.SCOVERAGE_COUNTER: 1122 if ldr.AttrReachable(s) { 1123 data := ldr.Data(s) 1124 if len(data) > 0 { 1125 ldr.Errorf(s, "should not be bss (size=%d type=%v special=%v)", len(data), ldr.SymType(s), ldr.AttrSpecial(s)) 1126 } 1127 putaixsym(ctxt, s, BSSSym) 1128 } 1129 1130 case st >= sym.SELFRXSECT && st < sym.SXREF: // data sections handled in dodata 1131 if ldr.AttrReachable(s) { 1132 putaixsym(ctxt, s, DataSym) 1133 } 1134 1135 case st == sym.SUNDEFEXT: 1136 putaixsym(ctxt, s, UndefinedSym) 1137 1138 case st == sym.SDYNIMPORT: 1139 if ldr.AttrReachable(s) { 1140 putaixsym(ctxt, s, UndefinedSym) 1141 } 1142 } 1143 } 1144 1145 for _, s := range ctxt.Textp { 1146 putaixsym(ctxt, s, TextSym) 1147 } 1148 1149 if ctxt.Debugvlog != 0 || *flagN { 1150 ctxt.Logf("symsize = %d\n", uint32(symSize)) 1151 } 1152 xfile.updatePreviousFile(ctxt, true) 1153 } 1154 1155 func (f *xcoffFile) genDynSym(ctxt *Link) { 1156 ldr := ctxt.loader 1157 var dynsyms []loader.Sym 1158 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ { 1159 if !ldr.AttrReachable(s) { 1160 continue 1161 } 1162 if t := ldr.SymType(s); t != sym.SHOSTOBJ && t != sym.SDYNIMPORT { 1163 continue 1164 } 1165 dynsyms = append(dynsyms, s) 1166 } 1167 1168 for _, s := range dynsyms { 1169 f.adddynimpsym(ctxt, s) 1170 1171 if _, ok := f.dynLibraries[ldr.SymDynimplib(s)]; !ok { 1172 f.dynLibraries[ldr.SymDynimplib(s)] = len(f.dynLibraries) 1173 } 1174 } 1175 } 1176 1177 // (*xcoffFile)adddynimpsym adds the dynamic symbol "s" to a XCOFF file. 1178 // A new symbol named s.Extname() is created to be the actual dynamic symbol 1179 // in the .loader section and in the symbol table as an External Reference. 1180 // The symbol "s" is transformed to SXCOFFTOC to end up in .data section. 1181 // However, there is no writing protection on those symbols and 1182 // it might need to be added. 1183 // TODO(aix): Handles dynamic symbols without library. 1184 func (f *xcoffFile) adddynimpsym(ctxt *Link, s loader.Sym) { 1185 // Check that library name is given. 1186 // Pattern is already checked when compiling. 1187 ldr := ctxt.loader 1188 if ctxt.IsInternal() && ldr.SymDynimplib(s) == "" { 1189 ctxt.Errorf(s, "imported symbol must have a given library") 1190 } 1191 1192 sb := ldr.MakeSymbolUpdater(s) 1193 sb.SetReachable(true) 1194 sb.SetType(sym.SXCOFFTOC) 1195 1196 // Create new dynamic symbol 1197 extsym := ldr.CreateSymForUpdate(ldr.SymExtname(s), 0) 1198 extsym.SetType(sym.SDYNIMPORT) 1199 extsym.SetDynimplib(ldr.SymDynimplib(s)) 1200 extsym.SetExtname(ldr.SymExtname(s)) 1201 extsym.SetDynimpvers(ldr.SymDynimpvers(s)) 1202 1203 // Add loader symbol 1204 lds := &xcoffLoaderSymbol{ 1205 sym: extsym.Sym(), 1206 smtype: XTY_IMP, 1207 smclas: XMC_DS, 1208 } 1209 if ldr.SymName(s) == "__n_pthreads" { 1210 // Currently, all imported symbols made by cgo_import_dynamic are 1211 // syscall functions, except __n_pthreads which is a variable. 1212 // TODO(aix): Find a way to detect variables imported by cgo. 1213 lds.smclas = XMC_RW 1214 } 1215 f.loaderSymbols = append(f.loaderSymbols, lds) 1216 1217 // Relocation to retrieve the external address 1218 sb.AddBytes(make([]byte, 8)) 1219 r, _ := sb.AddRel(objabi.R_ADDR) 1220 r.SetSym(extsym.Sym()) 1221 r.SetSiz(uint8(ctxt.Arch.PtrSize)) 1222 // TODO: maybe this could be 1223 // sb.SetSize(0) 1224 // sb.SetData(nil) 1225 // sb.AddAddr(ctxt.Arch, extsym.Sym()) 1226 // If the size is not 0 to begin with, I don't think the added 8 bytes 1227 // of zeros are necessary. 1228 } 1229 1230 // Xcoffadddynrel adds a dynamic relocation in a XCOFF file. 1231 // This relocation will be made by the loader. 1232 func Xcoffadddynrel(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool { 1233 if target.IsExternal() { 1234 return true 1235 } 1236 if ldr.SymType(s) <= sym.SPCLNTAB { 1237 ldr.Errorf(s, "cannot have a relocation to %s in a text section symbol", ldr.SymName(r.Sym())) 1238 return false 1239 } 1240 1241 xldr := &xcoffLoaderReloc{ 1242 sym: s, 1243 roff: r.Off(), 1244 } 1245 targ := r.Sym() 1246 var targType sym.SymKind 1247 if targ != 0 { 1248 targType = ldr.SymType(targ) 1249 } 1250 1251 switch r.Type() { 1252 default: 1253 ldr.Errorf(s, "unexpected .loader relocation to symbol: %s (type: %s)", ldr.SymName(targ), r.Type().String()) 1254 return false 1255 case objabi.R_ADDR: 1256 if ldr.SymType(s) == sym.SXCOFFTOC && targType == sym.SDYNIMPORT { 1257 // Imported symbol relocation 1258 for i, dynsym := range xfile.loaderSymbols { 1259 if ldr.SymName(dynsym.sym) == ldr.SymName(targ) { 1260 xldr.symndx = int32(i + 3) // +3 because of 3 section symbols 1261 break 1262 } 1263 } 1264 } else if t := ldr.SymType(s); t == sym.SDATA || t == sym.SNOPTRDATA || t == sym.SBUILDINFO || t == sym.SXCOFFTOC { 1265 switch ldr.SymSect(targ).Seg { 1266 default: 1267 ldr.Errorf(s, "unknown segment for .loader relocation with symbol %s", ldr.SymName(targ)) 1268 case &Segtext: 1269 case &Segrodata: 1270 xldr.symndx = 0 // .text 1271 case &Segdata: 1272 if targType == sym.SBSS || targType == sym.SNOPTRBSS { 1273 xldr.symndx = 2 // .bss 1274 } else { 1275 xldr.symndx = 1 // .data 1276 } 1277 } 1278 1279 } else { 1280 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)) 1281 return false 1282 } 1283 1284 xldr.rtype = 0x3F<<8 + XCOFF_R_POS 1285 } 1286 1287 xfile.Lock() 1288 xfile.loaderReloc = append(xfile.loaderReloc, xldr) 1289 xfile.Unlock() 1290 return true 1291 } 1292 1293 func (ctxt *Link) doxcoff() { 1294 ldr := ctxt.loader 1295 1296 // TOC 1297 toc := ldr.CreateSymForUpdate("TOC", 0) 1298 toc.SetType(sym.SXCOFFTOC) 1299 toc.SetVisibilityHidden(true) 1300 1301 // Add entry point to .loader symbols. 1302 ep := ldr.Lookup(*flagEntrySymbol, 0) 1303 if ep == 0 || !ldr.AttrReachable(ep) { 1304 Exitf("wrong entry point") 1305 } 1306 1307 xfile.loaderSymbols = append(xfile.loaderSymbols, &xcoffLoaderSymbol{ 1308 sym: ep, 1309 smtype: XTY_ENT | XTY_SD, 1310 smclas: XMC_DS, 1311 }) 1312 1313 xfile.genDynSym(ctxt) 1314 1315 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ { 1316 if strings.HasPrefix(ldr.SymName(s), "TOC.") { 1317 sb := ldr.MakeSymbolUpdater(s) 1318 sb.SetType(sym.SXCOFFTOC) 1319 } 1320 } 1321 1322 if ctxt.IsExternal() { 1323 // Change rt0_go name to match name in runtime/cgo:main(). 1324 rt0 := ldr.Lookup("runtime.rt0_go", 0) 1325 ldr.SetSymExtname(rt0, "runtime_rt0_go") 1326 1327 nsym := loader.Sym(ldr.NSym()) 1328 for s := loader.Sym(1); s < nsym; s++ { 1329 if !ldr.AttrCgoExport(s) { 1330 continue 1331 } 1332 if ldr.IsFileLocal(s) { 1333 panic("cgo_export on static symbol") 1334 } 1335 1336 if ldr.SymType(s) == sym.STEXT { 1337 // On AIX, a exported function must have two symbols: 1338 // - a .text symbol which must start with a ".". 1339 // - a .data symbol which is a function descriptor. 1340 name := ldr.SymExtname(s) 1341 ldr.SetSymExtname(s, "."+name) 1342 1343 desc := ldr.MakeSymbolUpdater(ldr.CreateExtSym(name, 0)) 1344 desc.SetReachable(true) 1345 desc.SetType(sym.SNOPTRDATA) 1346 desc.AddAddr(ctxt.Arch, s) 1347 desc.AddAddr(ctxt.Arch, toc.Sym()) 1348 desc.AddUint64(ctxt.Arch, 0) 1349 } 1350 } 1351 } 1352 } 1353 1354 // Loader section 1355 // Currently, this section is created from scratch when assembling the XCOFF file 1356 // according to information retrieved in xfile object. 1357 1358 // Create loader section and returns its size. 1359 func Loaderblk(ctxt *Link, off uint64) { 1360 xfile.writeLdrScn(ctxt, off) 1361 } 1362 1363 func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) { 1364 var symtab []*XcoffLdSym64 1365 var strtab []*XcoffLdStr64 1366 var importtab []*XcoffLdImportFile64 1367 var reloctab []*XcoffLdRel64 1368 var dynimpreloc []*XcoffLdRel64 1369 1370 // As the string table is updated in any loader subsection, 1371 // its length must be computed at the same time. 1372 stlen := uint32(0) 1373 1374 // Loader Header 1375 hdr := &XcoffLdHdr64{ 1376 Lversion: 2, 1377 Lsymoff: LDHDRSZ_64, 1378 } 1379 1380 ldr := ctxt.loader 1381 /* Symbol table */ 1382 for _, s := range f.loaderSymbols { 1383 lds := &XcoffLdSym64{ 1384 Loffset: uint32(stlen + 2), 1385 Lsmtype: s.smtype, 1386 Lsmclas: s.smclas, 1387 } 1388 sym := s.sym 1389 switch s.smtype { 1390 default: 1391 ldr.Errorf(sym, "unexpected loader symbol type: 0x%x", s.smtype) 1392 case XTY_ENT | XTY_SD: 1393 lds.Lvalue = uint64(ldr.SymValue(sym)) 1394 lds.Lscnum = f.getXCOFFscnum(ldr.SymSect(sym)) 1395 case XTY_IMP: 1396 lds.Lifile = int32(f.dynLibraries[ldr.SymDynimplib(sym)] + 1) 1397 } 1398 ldstr := &XcoffLdStr64{ 1399 size: uint16(len(ldr.SymName(sym)) + 1), // + null terminator 1400 name: ldr.SymName(sym), 1401 } 1402 stlen += uint32(2 + ldstr.size) // 2 = sizeof ldstr.size 1403 symtab = append(symtab, lds) 1404 strtab = append(strtab, ldstr) 1405 1406 } 1407 1408 hdr.Lnsyms = int32(len(symtab)) 1409 hdr.Lrldoff = hdr.Lsymoff + uint64(24*hdr.Lnsyms) // 24 = sizeof one symbol 1410 off := hdr.Lrldoff // current offset is the same of reloc offset 1411 1412 /* Reloc */ 1413 // Ensure deterministic order 1414 sort.Slice(f.loaderReloc, func(i, j int) bool { 1415 r1, r2 := f.loaderReloc[i], f.loaderReloc[j] 1416 if r1.sym != r2.sym { 1417 return r1.sym < r2.sym 1418 } 1419 if r1.roff != r2.roff { 1420 return r1.roff < r2.roff 1421 } 1422 if r1.rtype != r2.rtype { 1423 return r1.rtype < r2.rtype 1424 } 1425 return r1.symndx < r2.symndx 1426 }) 1427 1428 ep := ldr.Lookup(*flagEntrySymbol, 0) 1429 xldr := &XcoffLdRel64{ 1430 Lvaddr: uint64(ldr.SymValue(ep)), 1431 Lrtype: 0x3F00, 1432 Lrsecnm: f.getXCOFFscnum(ldr.SymSect(ep)), 1433 Lsymndx: 0, 1434 } 1435 off += 16 1436 reloctab = append(reloctab, xldr) 1437 1438 off += uint64(16 * len(f.loaderReloc)) 1439 for _, r := range f.loaderReloc { 1440 symp := r.sym 1441 if symp == 0 { 1442 panic("unexpected 0 sym value") 1443 } 1444 xldr = &XcoffLdRel64{ 1445 Lvaddr: uint64(ldr.SymValue(symp) + int64(r.roff)), 1446 Lrtype: r.rtype, 1447 Lsymndx: r.symndx, 1448 } 1449 1450 if ldr.SymSect(symp) != nil { 1451 xldr.Lrsecnm = f.getXCOFFscnum(ldr.SymSect(symp)) 1452 } 1453 1454 reloctab = append(reloctab, xldr) 1455 } 1456 1457 off += uint64(16 * len(dynimpreloc)) 1458 reloctab = append(reloctab, dynimpreloc...) 1459 1460 hdr.Lnreloc = int32(len(reloctab)) 1461 hdr.Limpoff = off 1462 1463 /* Import */ 1464 // Default import: /usr/lib:/lib 1465 ldimpf := &XcoffLdImportFile64{ 1466 Limpidpath: "/usr/lib:/lib", 1467 } 1468 off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter 1469 importtab = append(importtab, ldimpf) 1470 1471 // The map created by adddynimpsym associates the name to a number 1472 // This number represents the librairie index (- 1) in this import files section 1473 // Therefore, they must be sorted before being put inside the section 1474 libsOrdered := make([]string, len(f.dynLibraries)) 1475 for key, val := range f.dynLibraries { 1476 if libsOrdered[val] != "" { 1477 continue 1478 } 1479 libsOrdered[val] = key 1480 } 1481 1482 for _, lib := range libsOrdered { 1483 // lib string is defined as base.a/mem.o or path/base.a/mem.o 1484 n := strings.Split(lib, "/") 1485 path := "" 1486 base := n[len(n)-2] 1487 mem := n[len(n)-1] 1488 if len(n) > 2 { 1489 path = lib[:len(lib)-len(base)-len(mem)-2] 1490 1491 } 1492 ldimpf = &XcoffLdImportFile64{ 1493 Limpidpath: path, 1494 Limpidbase: base, 1495 Limpidmem: mem, 1496 } 1497 off += uint64(len(ldimpf.Limpidpath) + len(ldimpf.Limpidbase) + len(ldimpf.Limpidmem) + 3) // + null delimiter 1498 importtab = append(importtab, ldimpf) 1499 } 1500 1501 hdr.Lnimpid = int32(len(importtab)) 1502 hdr.Listlen = uint32(off - hdr.Limpoff) 1503 hdr.Lstoff = off 1504 hdr.Lstlen = stlen 1505 1506 /* Writing */ 1507 ctxt.Out.SeekSet(int64(globalOff)) 1508 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, hdr) 1509 1510 for _, s := range symtab { 1511 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s) 1512 1513 } 1514 for _, r := range reloctab { 1515 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, r) 1516 } 1517 for _, f := range importtab { 1518 ctxt.Out.WriteString(f.Limpidpath) 1519 ctxt.Out.Write8(0) 1520 ctxt.Out.WriteString(f.Limpidbase) 1521 ctxt.Out.Write8(0) 1522 ctxt.Out.WriteString(f.Limpidmem) 1523 ctxt.Out.Write8(0) 1524 } 1525 for _, s := range strtab { 1526 ctxt.Out.Write16(s.size) 1527 ctxt.Out.WriteString(s.name) 1528 ctxt.Out.Write8(0) // null terminator 1529 } 1530 1531 f.loaderSize = off + uint64(stlen) 1532 } 1533 1534 // XCOFF assembling and writing file 1535 1536 func (f *xcoffFile) writeFileHeader(ctxt *Link) { 1537 // File header 1538 f.xfhdr.Fmagic = U64_TOCMAGIC 1539 f.xfhdr.Fnscns = uint16(len(f.sections)) 1540 f.xfhdr.Ftimedat = 0 1541 1542 if !*FlagS { 1543 f.xfhdr.Fsymptr = uint64(f.symtabOffset) 1544 f.xfhdr.Fnsyms = int32(f.symbolCount) 1545 } 1546 1547 if ctxt.BuildMode == BuildModeExe && ctxt.LinkMode == LinkInternal { 1548 ldr := ctxt.loader 1549 f.xfhdr.Fopthdr = AOUTHSZ_EXEC64 1550 f.xfhdr.Fflags = F_EXEC 1551 1552 // auxiliary header 1553 f.xahdr.Ovstamp = 1 // based on dump -o 1554 f.xahdr.Omagic = 0x10b 1555 copy(f.xahdr.Omodtype[:], "1L") 1556 entry := ldr.Lookup(*flagEntrySymbol, 0) 1557 f.xahdr.Oentry = uint64(ldr.SymValue(entry)) 1558 f.xahdr.Osnentry = f.getXCOFFscnum(ldr.SymSect(entry)) 1559 toc := ldr.Lookup("TOC", 0) 1560 f.xahdr.Otoc = uint64(ldr.SymValue(toc)) 1561 f.xahdr.Osntoc = f.getXCOFFscnum(ldr.SymSect(toc)) 1562 1563 f.xahdr.Oalgntext = int16(logBase2(int(XCOFFSECTALIGN))) 1564 f.xahdr.Oalgndata = 0x5 1565 1566 binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr) 1567 binary.Write(ctxt.Out, binary.BigEndian, &f.xahdr) 1568 } else { 1569 f.xfhdr.Fopthdr = 0 1570 binary.Write(ctxt.Out, binary.BigEndian, &f.xfhdr) 1571 } 1572 1573 } 1574 1575 func xcoffwrite(ctxt *Link) { 1576 ctxt.Out.SeekSet(0) 1577 1578 xfile.writeFileHeader(ctxt) 1579 1580 for _, sect := range xfile.sections { 1581 sect.write(ctxt) 1582 } 1583 } 1584 1585 // Generate XCOFF assembly file. 1586 func asmbXcoff(ctxt *Link) { 1587 ctxt.Out.SeekSet(0) 1588 fileoff := int64(Segdwarf.Fileoff + Segdwarf.Filelen) 1589 fileoff = int64(Rnd(int64(fileoff), int64(*FlagRound))) 1590 1591 xfile.sectNameToScnum = make(map[string]int16) 1592 1593 // Add sections 1594 s := xfile.addSection(".text", Segtext.Vaddr, Segtext.Length, Segtext.Fileoff, STYP_TEXT) 1595 xfile.xahdr.Otextstart = s.Svaddr 1596 xfile.xahdr.Osntext = xfile.sectNameToScnum[".text"] 1597 xfile.xahdr.Otsize = s.Ssize 1598 xfile.sectText = s 1599 1600 segdataVaddr := Segdata.Vaddr 1601 segdataFilelen := Segdata.Filelen 1602 segdataFileoff := Segdata.Fileoff 1603 segbssFilelen := Segdata.Length - Segdata.Filelen 1604 if len(Segrelrodata.Sections) > 0 { 1605 // Merge relro segment to data segment as 1606 // relro data are inside data segment on AIX. 1607 segdataVaddr = Segrelrodata.Vaddr 1608 segdataFileoff = Segrelrodata.Fileoff 1609 segdataFilelen = Segdata.Vaddr + Segdata.Filelen - Segrelrodata.Vaddr 1610 } 1611 1612 s = xfile.addSection(".data", segdataVaddr, segdataFilelen, segdataFileoff, STYP_DATA) 1613 xfile.xahdr.Odatastart = s.Svaddr 1614 xfile.xahdr.Osndata = xfile.sectNameToScnum[".data"] 1615 xfile.xahdr.Odsize = s.Ssize 1616 xfile.sectData = s 1617 1618 s = xfile.addSection(".bss", segdataVaddr+segdataFilelen, segbssFilelen, 0, STYP_BSS) 1619 xfile.xahdr.Osnbss = xfile.sectNameToScnum[".bss"] 1620 xfile.xahdr.Obsize = s.Ssize 1621 xfile.sectBss = s 1622 1623 if ctxt.LinkMode == LinkExternal { 1624 var tbss *sym.Section 1625 for _, s := range Segdata.Sections { 1626 if s.Name == ".tbss" { 1627 tbss = s 1628 break 1629 } 1630 } 1631 s = xfile.addSection(".tbss", tbss.Vaddr, tbss.Length, 0, STYP_TBSS) 1632 } 1633 1634 // add dwarf sections 1635 for _, sect := range Segdwarf.Sections { 1636 xfile.addDwarfSection(sect) 1637 } 1638 1639 // add and write remaining sections 1640 if ctxt.LinkMode == LinkInternal { 1641 // Loader section 1642 if ctxt.BuildMode == BuildModeExe { 1643 Loaderblk(ctxt, uint64(fileoff)) 1644 s = xfile.addSection(".loader", 0, xfile.loaderSize, uint64(fileoff), STYP_LOADER) 1645 xfile.xahdr.Osnloader = xfile.sectNameToScnum[".loader"] 1646 1647 // Update fileoff for symbol table 1648 fileoff += int64(xfile.loaderSize) 1649 } 1650 } 1651 1652 // Create Symbol table 1653 xfile.asmaixsym(ctxt) 1654 1655 if ctxt.LinkMode == LinkExternal { 1656 xfile.emitRelocations(ctxt, fileoff) 1657 } 1658 1659 // Write Symbol table 1660 xfile.symtabOffset = ctxt.Out.Offset() 1661 for _, s := range xfile.symtabSym { 1662 binary.Write(ctxt.Out, ctxt.Arch.ByteOrder, s) 1663 } 1664 // write string table 1665 xfile.stringTable.write(ctxt.Out) 1666 1667 // write headers 1668 xcoffwrite(ctxt) 1669 } 1670 1671 // emitRelocations emits relocation entries for go.o in external linking. 1672 func (f *xcoffFile) emitRelocations(ctxt *Link, fileoff int64) { 1673 ctxt.Out.SeekSet(fileoff) 1674 for ctxt.Out.Offset()&7 != 0 { 1675 ctxt.Out.Write8(0) 1676 } 1677 1678 ldr := ctxt.loader 1679 // relocsect relocates symbols from first in section sect, and returns 1680 // the total number of relocations emitted. 1681 relocsect := func(sect *sym.Section, syms []loader.Sym, base uint64) uint32 { 1682 // ctxt.Logf("%s 0x%x\n", sect.Name, sect.Vaddr) 1683 // If main section has no bits, nothing to relocate. 1684 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 1685 return 0 1686 } 1687 sect.Reloff = uint64(ctxt.Out.Offset()) 1688 for i, s := range syms { 1689 if !ldr.AttrReachable(s) { 1690 continue 1691 } 1692 if uint64(ldr.SymValue(s)) >= sect.Vaddr { 1693 syms = syms[i:] 1694 break 1695 } 1696 } 1697 eaddr := int64(sect.Vaddr + sect.Length) 1698 for _, s := range syms { 1699 if !ldr.AttrReachable(s) { 1700 continue 1701 } 1702 if ldr.SymValue(s) >= int64(eaddr) { 1703 break 1704 } 1705 1706 // Compute external relocations on the go, and pass to Xcoffreloc1 to stream out. 1707 // Relocation must be ordered by address, so create a list of sorted indices. 1708 relocs := ldr.Relocs(s) 1709 sorted := make([]int, relocs.Count()) 1710 for i := 0; i < relocs.Count(); i++ { 1711 sorted[i] = i 1712 } 1713 sort.Slice(sorted, func(i, j int) bool { 1714 return relocs.At(sorted[i]).Off() < relocs.At(sorted[j]).Off() 1715 }) 1716 1717 for _, ri := range sorted { 1718 r := relocs.At(ri) 1719 rr, ok := extreloc(ctxt, ldr, s, r) 1720 if !ok { 1721 continue 1722 } 1723 if rr.Xsym == 0 { 1724 ldr.Errorf(s, "missing xsym in relocation") 1725 continue 1726 } 1727 if ldr.SymDynid(rr.Xsym) < 0 { 1728 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)) 1729 } 1730 if !thearch.Xcoffreloc1(ctxt.Arch, ctxt.Out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-base)) { 1731 ldr.Errorf(s, "unsupported obj reloc %d(%s)/%d to %s", r.Type(), r.Type(), r.Siz(), ldr.SymName(r.Sym())) 1732 } 1733 } 1734 } 1735 sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff 1736 return uint32(sect.Rellen) / RELSZ_64 1737 } 1738 sects := []struct { 1739 xcoffSect *XcoffScnHdr64 1740 segs []*sym.Segment 1741 }{ 1742 {f.sectText, []*sym.Segment{&Segtext}}, 1743 {f.sectData, []*sym.Segment{&Segrelrodata, &Segdata}}, 1744 } 1745 for _, s := range sects { 1746 s.xcoffSect.Srelptr = uint64(ctxt.Out.Offset()) 1747 n := uint32(0) 1748 for _, seg := range s.segs { 1749 for _, sect := range seg.Sections { 1750 if sect.Name == ".text" { 1751 n += relocsect(sect, ctxt.Textp, 0) 1752 } else { 1753 n += relocsect(sect, ctxt.datap, 0) 1754 } 1755 } 1756 } 1757 s.xcoffSect.Snreloc += n 1758 } 1759 1760 dwarfLoop: 1761 for i := 0; i < len(Segdwarf.Sections); i++ { 1762 sect := Segdwarf.Sections[i] 1763 si := dwarfp[i] 1764 if si.secSym() != loader.Sym(sect.Sym) || 1765 ldr.SymSect(si.secSym()) != sect { 1766 panic("inconsistency between dwarfp and Segdwarf") 1767 } 1768 for _, xcoffSect := range f.sections { 1769 _, subtyp := xcoffGetDwarfSubtype(sect.Name) 1770 if xcoffSect.Sflags&0xF0000 == subtyp { 1771 xcoffSect.Srelptr = uint64(ctxt.Out.Offset()) 1772 xcoffSect.Snreloc = relocsect(sect, si.syms, sect.Vaddr) 1773 continue dwarfLoop 1774 } 1775 } 1776 Errorf(nil, "emitRelocations: could not find %q section", sect.Name) 1777 } 1778 } 1779 1780 // xcoffCreateExportFile creates a file with exported symbols for 1781 // -Wl,-bE option. 1782 // ld won't export symbols unless they are listed in an export file. 1783 func xcoffCreateExportFile(ctxt *Link) (fname string) { 1784 fname = filepath.Join(*flagTmpdir, "export_file.exp") 1785 var buf bytes.Buffer 1786 1787 ldr := ctxt.loader 1788 for s, nsym := loader.Sym(1), loader.Sym(ldr.NSym()); s < nsym; s++ { 1789 if !ldr.AttrCgoExport(s) { 1790 continue 1791 } 1792 extname := ldr.SymExtname(s) 1793 if !strings.HasPrefix(extname, "._cgoexp_") { 1794 continue 1795 } 1796 if ldr.IsFileLocal(s) { 1797 continue // Only export non-static symbols 1798 } 1799 1800 // Retrieve the name of the initial symbol 1801 // exported by cgo. 1802 // The corresponding Go symbol is: 1803 // _cgoexp_hashcode_symname. 1804 name := strings.SplitN(extname, "_", 4)[3] 1805 1806 buf.Write([]byte(name + "\n")) 1807 } 1808 1809 err := os.WriteFile(fname, buf.Bytes(), 0666) 1810 if err != nil { 1811 Errorf(nil, "WriteFile %s failed: %v", fname, err) 1812 } 1813 1814 return fname 1815 }