func gentext() { if !ld.DynlinkingGo() && ld.Buildmode != ld.BuildmodePIE { return } thunkfunc := ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0) thunkfunc.Type = obj.STEXT thunkfunc.Local = true thunkfunc.Reachable = true o := func(op ...uint8) { for _, op1 := range op { ld.Adduint8(ld.Ctxt, thunkfunc, op1) } } // 8b 0c 24 mov (%esp),%ecx o(0x8b, 0x0c, 0x24) // c3 ret o(0xc3) if ld.Ctxt.Etextp != nil { ld.Ctxt.Etextp.Next = thunkfunc } else { ld.Ctxt.Textp = thunkfunc } ld.Ctxt.Etextp = thunkfunc }
func archinit(ctxt *ld.Link) { // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" { ld.Linkmode = ld.LinkInternal } if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() { ld.Linkmode = ld.LinkExternal } switch ld.HEADTYPE { default: ld.Exitf("unknown -H option: %v", ld.HEADTYPE) case obj.Hlinux: // s390x ELF ld.Elfinit(ctxt) ld.HEADR = ld.ELFRESERVE if *ld.FlagTextAddr == -1 { *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR) } if *ld.FlagDataAddr == -1 { *ld.FlagDataAddr = 0 } if *ld.FlagRound == -1 { *ld.FlagRound = 0x10000 } } if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 { fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound)) } }
func gentext() { if ld.DynlinkingGo() { genaddmoduledata() } if ld.Linkmode == ld.LinkInternal { genplt() } }
func gentext() { if !ld.DynlinkingGo() { return } addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0) if addmoduledata.Type == obj.STEXT { // we're linking a module containing the runtime -> no need for // an init function return } addmoduledata.Attr |= ld.AttrReachable initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0) initfunc.Type = obj.STEXT initfunc.Attr |= ld.AttrLocal initfunc.Attr |= ld.AttrReachable o := func(op uint32) { ld.Adduint32(ld.Ctxt, initfunc, op) } // 0000000000000000 <local.dso_init>: // 0: 90000000 adrp x0, 0 <runtime.firstmoduledata> // 0: R_AARCH64_ADR_PREL_PG_HI21 local.moduledata // 4: 91000000 add x0, x0, #0x0 // 4: R_AARCH64_ADD_ABS_LO12_NC local.moduledata o(0x90000000) o(0x91000000) rel := ld.Addrel(initfunc) rel.Off = 0 rel.Siz = 8 rel.Sym = ld.Ctxt.Moduledata rel.Type = obj.R_ADDRARM64 // 8: 14000000 bl 0 <runtime.addmoduledata> // 8: R_AARCH64_CALL26 runtime.addmoduledata o(0x14000000) rel = ld.Addrel(initfunc) rel.Off = 8 rel.Siz = 4 rel.Sym = ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0) rel.Type = obj.R_CALLARM64 // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference if ld.Ctxt.Etextp != nil { ld.Ctxt.Etextp.Next = initfunc } else { ld.Ctxt.Textp = initfunc } ld.Ctxt.Etextp = initfunc initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Attr |= ld.AttrReachable initarray_entry.Attr |= ld.AttrLocal initarray_entry.Type = obj.SINITARR ld.Addaddr(ld.Ctxt, initarray_entry, initfunc) }
// gentext generates assembly to append the local moduledata to the global // moduledata linked list at initialization time. This is only done if the runtime // is in a different module. // // <go.link.addmoduledata>: // larl %r2, <local.moduledata> // jg <runtime.addmoduledata@plt> // undef // // The job of appending the moduledata is delegated to runtime.addmoduledata. func gentext(ctxt *ld.Link) { if !ld.DynlinkingGo() { return } addmoduledata := ld.Linklookup(ctxt, "runtime.addmoduledata", 0) if addmoduledata.Type == obj.STEXT { // we're linking a module containing the runtime -> no need for // an init function return } addmoduledata.Attr |= ld.AttrReachable initfunc := ld.Linklookup(ctxt, "go.link.addmoduledata", 0) initfunc.Type = obj.STEXT initfunc.Attr |= ld.AttrLocal initfunc.Attr |= ld.AttrReachable // larl %r2, <local.moduledata> ld.Adduint8(ctxt, initfunc, 0xc0) ld.Adduint8(ctxt, initfunc, 0x20) lmd := ld.Addrel(initfunc) lmd.Off = int32(initfunc.Size) lmd.Siz = 4 lmd.Sym = ctxt.Moduledata lmd.Type = obj.R_PCREL lmd.Variant = ld.RV_390_DBL lmd.Add = 2 + int64(lmd.Siz) ld.Adduint32(ctxt, initfunc, 0) // jg <runtime.addmoduledata[@plt]> ld.Adduint8(ctxt, initfunc, 0xc0) ld.Adduint8(ctxt, initfunc, 0xf4) rel := ld.Addrel(initfunc) rel.Off = int32(initfunc.Size) rel.Siz = 4 rel.Sym = ld.Linklookup(ctxt, "runtime.addmoduledata", 0) rel.Type = obj.R_CALL rel.Variant = ld.RV_390_DBL rel.Add = 2 + int64(rel.Siz) ld.Adduint32(ctxt, initfunc, 0) // undef (for debugging) ld.Adduint32(ctxt, initfunc, 0) ctxt.Textp = append(ctxt.Textp, initfunc) initarray_entry := ld.Linklookup(ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Attr |= ld.AttrLocal initarray_entry.Attr |= ld.AttrReachable initarray_entry.Type = obj.SINITARR ld.Addaddr(ctxt, initarray_entry, initfunc) }
func gentext() { if !ld.DynlinkingGo() { return } addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0) if addmoduledata.Type == obj.STEXT { // we're linking a module containing the runtime -> no need for // an init function return } addmoduledata.Reachable = true initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0) initfunc.Type = obj.STEXT initfunc.Local = true initfunc.Reachable = true o := func(op uint32) { ld.Adduint32(ld.Ctxt, initfunc, op) } o(0xe59f0004) o(0xe08f0000) o(0xeafffffe) rel := ld.Addrel(initfunc) rel.Off = 8 rel.Siz = 4 rel.Sym = ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0) rel.Type = obj.R_CALLARM rel.Add = 0xeafffffe // vomit o(0x00000000) rel = ld.Addrel(initfunc) rel.Off = 12 rel.Siz = 4 rel.Sym = ld.Ctxt.Moduledata rel.Type = obj.R_PCREL rel.Add = 4 if ld.Ctxt.Etextp != nil { ld.Ctxt.Etextp.Next = initfunc } else { ld.Ctxt.Textp = initfunc } ld.Ctxt.Etextp = initfunc initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Reachable = true initarray_entry.Local = true initarray_entry.Type = obj.SINITARR ld.Addaddr(ld.Ctxt, initarray_entry, initfunc) }
func gentext(ctxt *ld.Link) { if !ld.DynlinkingGo() { return } addmoduledata := ld.Linklookup(ctxt, "runtime.addmoduledata", 0) if addmoduledata.Type == obj.STEXT { // we're linking a module containing the runtime -> no need for // an init function return } addmoduledata.Attr |= ld.AttrReachable initfunc := ld.Linklookup(ctxt, "go.link.addmoduledata", 0) initfunc.Type = obj.STEXT initfunc.Attr |= ld.AttrLocal initfunc.Attr |= ld.AttrReachable o := func(op uint32) { ld.Adduint32(ctxt, initfunc, op) } o(0xe59f0004) o(0xe08f0000) o(0xeafffffe) rel := ld.Addrel(initfunc) rel.Off = 8 rel.Siz = 4 rel.Sym = ld.Linklookup(ctxt, "runtime.addmoduledata", 0) rel.Type = obj.R_CALLARM rel.Add = 0xeafffffe // vomit o(0x00000000) rel = ld.Addrel(initfunc) rel.Off = 12 rel.Siz = 4 rel.Sym = ctxt.Moduledata rel.Type = obj.R_PCREL rel.Add = 4 ctxt.Textp = append(ctxt.Textp, initfunc) initarray_entry := ld.Linklookup(ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Attr |= ld.AttrReachable initarray_entry.Attr |= ld.AttrLocal initarray_entry.Type = obj.SINITARR ld.Addaddr(ctxt, initarray_entry, initfunc) }
func gentext() { if !ld.DynlinkingGo() { return } addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0) if addmoduledata.Type == obj.STEXT { // we're linking a module containing the runtime -> no need for // an init function return } addmoduledata.Reachable = true initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0) initfunc.Type = obj.STEXT initfunc.Local = true initfunc.Reachable = true o := func(op ...uint8) { for _, op1 := range op { ld.Adduint8(ld.Ctxt, initfunc, op1) } } // 0000000000000000 <local.dso_init>: // 0: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 7 <local.dso_init+0x7> // 3: R_X86_64_PC32 runtime.firstmoduledata-0x4 o(0x48, 0x8d, 0x3d) ld.Addpcrelplus(ld.Ctxt, initfunc, ld.Ctxt.Moduledata, 0) // 7: e8 00 00 00 00 callq c <local.dso_init+0xc> // 8: R_X86_64_PLT32 runtime.addmoduledata-0x4 o(0xe8) Addcall(ld.Ctxt, initfunc, addmoduledata) // c: c3 retq o(0xc3) if ld.Ctxt.Etextp != nil { ld.Ctxt.Etextp.Next = initfunc } else { ld.Ctxt.Textp = initfunc } ld.Ctxt.Etextp = initfunc initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Reachable = true initarray_entry.Local = true initarray_entry.Type = obj.SINITARR ld.Addaddr(ld.Ctxt, initarray_entry, initfunc) }
func archinit() { // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" { ld.Linkmode = ld.LinkInternal } if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() { ld.Linkmode = ld.LinkExternal } switch ld.HEADTYPE { default: if ld.Linkmode == ld.LinkAuto { ld.Linkmode = ld.LinkInternal } if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" { log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE))) } case obj.Hlinux, obj.Hfreebsd, obj.Hnacl, obj.Hdarwin: break } switch ld.HEADTYPE { default: ld.Exitf("unknown -H option: %v", ld.HEADTYPE) case obj.Hplan9: /* plan 9 */ ld.HEADR = 32 if ld.INITTEXT == -1 { ld.INITTEXT = 4128 } if ld.INITDAT == -1 { ld.INITDAT = 0 } if ld.INITRND == -1 { ld.INITRND = 4096 } case obj.Hlinux, /* arm elf */ obj.Hfreebsd, obj.Hnetbsd, obj.Hopenbsd: ld.Debug['d'] = 0 // with dynamic linking ld.Elfinit() ld.HEADR = ld.ELFRESERVE if ld.INITTEXT == -1 { ld.INITTEXT = 0x10000 + int64(ld.HEADR) } if ld.INITDAT == -1 { ld.INITDAT = 0 } if ld.INITRND == -1 { ld.INITRND = 4096 } case obj.Hnacl: ld.Elfinit() ld.HEADR = 0x10000 ld.Funcalign = 16 if ld.INITTEXT == -1 { ld.INITTEXT = 0x20000 } if ld.INITDAT == -1 { ld.INITDAT = 0 } if ld.INITRND == -1 { ld.INITRND = 0x10000 } case obj.Hdarwin: /* apple MACH */ ld.Debug['w'] = 1 // disable DWARF generation ld.Machoinit() ld.HEADR = ld.INITIAL_MACHO_HEADR if ld.INITTEXT == -1 { ld.INITTEXT = 4096 + int64(ld.HEADR) } if ld.INITDAT == -1 { ld.INITDAT = 0 } if ld.INITRND == -1 { ld.INITRND = 4096 } } if ld.INITDAT != 0 && ld.INITRND != 0 { fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND)) } }
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { if ld.Linkmode == ld.LinkExternal { switch r.Type { default: return -1 case obj.R_ARM64_GOTPCREL: var o1, o2 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o1 = uint32(*val >> 32) o2 = uint32(*val) } else { o1 = uint32(*val) o2 = uint32(*val >> 32) } // Any relocation against a function symbol is redirected to // be against a local symbol instead (see putelfsym in // symtab.go) but unfortunately the system linker was buggy // when confronted with a R_AARCH64_ADR_GOT_PAGE relocation // against a local symbol until May 2015 // (https://sourceware.org/bugzilla/show_bug.cgi?id=18270). So // we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp; // add + R_ADDRARM64. if !(r.Sym.Version != 0 || (r.Sym.Type&obj.SHIDDEN != 0) || r.Sym.Attr.Local()) && r.Sym.Type == obj.STEXT && ld.DynlinkingGo() { if o2&0xffc00000 != 0xf9400000 { ld.Ctxt.Diag("R_ARM64_GOTPCREL against unexpected instruction %x", o2) } o2 = 0x91000000 | (o2 & 0x000003ff) r.Type = obj.R_ADDRARM64 } if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o1)<<32 | int64(o2) } else { *val = int64(o2)<<32 | int64(o1) } fallthrough case obj.R_ADDRARM64: r.Done = 0 // set up addend for eventual relocation via outer symbol. rs := r.Sym r.Xadd = r.Add for rs.Outer != nil { r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer) rs = rs.Outer } if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil { ld.Diag("missing section for %s", rs.Name) } r.Xsym = rs // Note: ld64 currently has a bug that any non-zero addend for BR26 relocation // will make the linking fail because it thinks the code is not PIC even though // the BR26 relocation should be fully resolved at link time. // That is the reason why the next if block is disabled. When the bug in ld64 // is fixed, we can enable this block and also enable duff's device in cmd/7g. if false && ld.HEADTYPE == obj.Hdarwin { var o0, o1 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o0 = uint32(*val >> 32) o1 = uint32(*val) } else { o0 = uint32(*val) o1 = uint32(*val >> 32) } // Mach-O wants the addend to be encoded in the instruction // Note that although Mach-O supports ARM64_RELOC_ADDEND, it // can only encode 24-bit of signed addend, but the instructions // supports 33-bit of signed addend, so we always encode the // addend in place. o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5) o1 |= uint32(r.Xadd&0xfff) << 10 r.Xadd = 0 // when laid out, the instruction order must always be o1, o2. if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o0)<<32 | int64(o1) } else { *val = int64(o1)<<32 | int64(o0) } } return 0 case obj.R_CALLARM64, obj.R_ARM64_TLS_LE, obj.R_ARM64_TLS_IE: r.Done = 0 r.Xsym = r.Sym r.Xadd = r.Add return 0 } } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 case obj.R_ADDRARM64: t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff) if t >= 1<<32 || t < -1<<32 { ld.Diag("program too large, address relocation distance = %d", t) } var o0, o1 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o0 = uint32(*val >> 32) o1 = uint32(*val) } else { o0 = uint32(*val) o1 = uint32(*val >> 32) } o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5) o1 |= uint32(t&0xfff) << 10 // when laid out, the instruction order must always be o1, o2. if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o0)<<32 | int64(o1) } else { *val = int64(o1)<<32 | int64(o0) } return 0 case obj.R_ARM64_TLS_LE: r.Done = 0 if ld.HEADTYPE != obj.Hlinux { ld.Diag("TLS reloc on unsupported OS %s", ld.Headstr(int(ld.HEADTYPE))) } // The TCB is two pointers. This is not documented anywhere, but is // de facto part of the ABI. v := r.Sym.Value + int64(2*ld.Thearch.Ptrsize) if v < 0 || v >= 32678 { ld.Diag("TLS offset out of range %d", v) } *val |= v << 5 return 0 case obj.R_CALLARM64: t := (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off)) if t >= 1<<27 || t < -1<<27 { ld.Diag("program too large, call relocation distance = %d", t) } *val |= (t >> 2) & 0x03ffffff return 0 } return -1 }
func elfreloc1(r *ld.Reloc, sectoff int64) int { ld.Thearch.Vput(uint64(sectoff)) elfsym := r.Xsym.ElfsymForReloc() switch r.Type { default: return -1 case obj.R_ADDR: if r.Siz == 4 { ld.Thearch.Vput(ld.R_X86_64_32 | uint64(elfsym)<<32) } else if r.Siz == 8 { ld.Thearch.Vput(ld.R_X86_64_64 | uint64(elfsym)<<32) } else { return -1 } case obj.R_TLS_LE: if r.Siz == 4 { ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32) } else { return -1 } case obj.R_TLS_IE: if r.Siz == 4 { ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32) } else { return -1 } case obj.R_CALL: if r.Siz == 4 { if r.Xsym.Type == obj.SDYNIMPORT { if ld.DynlinkingGo() { ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32) } else { ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32) } } else { ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32) } } else { return -1 } case obj.R_PCREL: if r.Siz == 4 { if r.Xsym.Type == obj.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC { ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32) } else { ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32) } } else { return -1 } case obj.R_GOTPCREL: if r.Siz == 4 { ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32) } else { return -1 } } ld.Thearch.Vput(uint64(r.Xadd)) return 0 }
func gentext() { if !ld.DynlinkingGo() && ld.Buildmode != ld.BuildmodePIE && ld.Buildmode != ld.BuildmodeCShared { return } thunkfunc := ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0) thunkfunc.Type = obj.STEXT thunkfunc.Local = true thunkfunc.Reachable = true o := func(op ...uint8) { for _, op1 := range op { ld.Adduint8(ld.Ctxt, thunkfunc, op1) } } // 8b 0c 24 mov (%esp),%ecx o(0x8b, 0x0c, 0x24) // c3 ret o(0xc3) if ld.Ctxt.Etextp != nil { ld.Ctxt.Etextp.Next = thunkfunc } else { ld.Ctxt.Textp = thunkfunc } ld.Ctxt.Etextp = thunkfunc addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0) if addmoduledata.Type == obj.STEXT { // we're linking a module containing the runtime -> no need for // an init function return } addmoduledata.Reachable = true initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0) initfunc.Type = obj.STEXT initfunc.Local = true initfunc.Reachable = true o = func(op ...uint8) { for _, op1 := range op { ld.Adduint8(ld.Ctxt, initfunc, op1) } } // go.link.addmoduledata: // 53 push %ebx // e8 00 00 00 00 call __x86.get_pc_thunk.cx + R_CALL __x86.get_pc_thunk.cx // 8d 81 00 00 00 00 lea 0x0(%ecx), %eax + R_PCREL ld.Ctxt.Moduledata // 8d 99 00 00 00 00 lea 0x0(%ecx), %ebx + R_GOTPC _GLOBAL_OFFSET_TABLE_ // e8 00 00 00 00 call runtime.addmoduledata@plt + R_CALL runtime.addmoduledata // 5b pop %ebx // c3 ret o(0x53) o(0xe8) addcall(ld.Ctxt, initfunc, ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0)) o(0x8d, 0x81) ld.Addpcrelplus(ld.Ctxt, initfunc, ld.Ctxt.Moduledata, 6) o(0x8d, 0x99) i := initfunc.Size initfunc.Size += 4 ld.Symgrow(ld.Ctxt, initfunc, initfunc.Size) r := ld.Addrel(initfunc) r.Sym = ld.Linklookup(ld.Ctxt, "_GLOBAL_OFFSET_TABLE_", 0) r.Off = int32(i) r.Type = obj.R_PCREL r.Add = 12 r.Siz = 4 o(0xe8) addcall(ld.Ctxt, initfunc, addmoduledata) o(0x5b) o(0xc3) ld.Ctxt.Etextp.Next = initfunc ld.Ctxt.Etextp = initfunc initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Reachable = true initarray_entry.Local = true initarray_entry.Type = obj.SINITARR ld.Addaddr(ld.Ctxt, initarray_entry, initfunc) }
func gentext(ctxt *ld.Link) { if !ld.DynlinkingGo() && ld.Buildmode != ld.BuildmodePIE && ld.Buildmode != ld.BuildmodeCShared { return } // Generate little thunks that load the PC of the next instruction into a register. for _, r := range [...]struct { name string num uint8 }{ {"ax", 0}, {"cx", 1}, {"dx", 2}, {"bx", 3}, // sp {"bp", 5}, {"si", 6}, {"di", 7}, } { thunkfunc := ld.Linklookup(ctxt, "__x86.get_pc_thunk."+r.name, 0) thunkfunc.Type = obj.STEXT thunkfunc.Attr |= ld.AttrLocal thunkfunc.Attr |= ld.AttrReachable //TODO: remove? o := func(op ...uint8) { for _, op1 := range op { ld.Adduint8(ctxt, thunkfunc, op1) } } // 8b 04 24 mov (%esp),%eax // Destination register is in bits 3-5 of the middle byte, so add that in. o(0x8b, 0x04+r.num<<3, 0x24) // c3 ret o(0xc3) ctxt.Textp = append(ctxt.Textp, thunkfunc) } addmoduledata := ld.Linklookup(ctxt, "runtime.addmoduledata", 0) if addmoduledata.Type == obj.STEXT { // we're linking a module containing the runtime -> no need for // an init function return } addmoduledata.Attr |= ld.AttrReachable initfunc := ld.Linklookup(ctxt, "go.link.addmoduledata", 0) initfunc.Type = obj.STEXT initfunc.Attr |= ld.AttrLocal initfunc.Attr |= ld.AttrReachable o := func(op ...uint8) { for _, op1 := range op { ld.Adduint8(ctxt, initfunc, op1) } } // go.link.addmoduledata: // 53 push %ebx // e8 00 00 00 00 call __x86.get_pc_thunk.cx + R_CALL __x86.get_pc_thunk.cx // 8d 81 00 00 00 00 lea 0x0(%ecx), %eax + R_PCREL ctxt.Moduledata // 8d 99 00 00 00 00 lea 0x0(%ecx), %ebx + R_GOTPC _GLOBAL_OFFSET_TABLE_ // e8 00 00 00 00 call runtime.addmoduledata@plt + R_CALL runtime.addmoduledata // 5b pop %ebx // c3 ret o(0x53) o(0xe8) addcall(ctxt, initfunc, ld.Linklookup(ctxt, "__x86.get_pc_thunk.cx", 0)) o(0x8d, 0x81) ld.Addpcrelplus(ctxt, initfunc, ctxt.Moduledata, 6) o(0x8d, 0x99) i := initfunc.Size initfunc.Size += 4 ld.Symgrow(ctxt, initfunc, initfunc.Size) r := ld.Addrel(initfunc) r.Sym = ld.Linklookup(ctxt, "_GLOBAL_OFFSET_TABLE_", 0) r.Off = int32(i) r.Type = obj.R_PCREL r.Add = 12 r.Siz = 4 o(0xe8) addcall(ctxt, initfunc, addmoduledata) o(0x5b) o(0xc3) ctxt.Textp = append(ctxt.Textp, initfunc) initarray_entry := ld.Linklookup(ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Attr |= ld.AttrReachable initarray_entry.Attr |= ld.AttrLocal initarray_entry.Type = obj.SINITARR ld.Addaddr(ctxt, initarray_entry, initfunc) }
func archinit(ctxt *ld.Link) { // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" { ld.Linkmode = ld.LinkInternal } if ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE || ld.DynlinkingGo() { ld.Linkmode = ld.LinkExternal got := ld.Linklookup(ctxt, "_GLOBAL_OFFSET_TABLE_", 0) got.Type = obj.SDYNIMPORT got.Attr |= ld.AttrReachable } switch ld.HEADTYPE { default: if ld.Linkmode == ld.LinkAuto { ld.Linkmode = ld.LinkInternal } if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" { log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE))) } case obj.Hdarwin, obj.Hfreebsd, obj.Hlinux, obj.Hnetbsd, obj.Hopenbsd, obj.Hwindows: break } switch ld.HEADTYPE { default: ld.Exitf("unknown -H option: %v", ld.HEADTYPE) case obj.Hplan9: /* plan 9 */ ld.HEADR = 32 if *ld.FlagTextAddr == -1 { *ld.FlagTextAddr = 4096 + 32 } if *ld.FlagDataAddr == -1 { *ld.FlagDataAddr = 0 } if *ld.FlagRound == -1 { *ld.FlagRound = 4096 } case obj.Hdarwin: /* apple MACH */ ld.Machoinit() ld.HEADR = ld.INITIAL_MACHO_HEADR if *ld.FlagTextAddr == -1 { *ld.FlagTextAddr = 4096 + int64(ld.HEADR) } if *ld.FlagDataAddr == -1 { *ld.FlagDataAddr = 0 } if *ld.FlagRound == -1 { *ld.FlagRound = 4096 } case obj.Hlinux, /* elf32 executable */ obj.Hfreebsd, obj.Hnetbsd, obj.Hopenbsd: ld.Elfinit(ctxt) ld.HEADR = ld.ELFRESERVE if *ld.FlagTextAddr == -1 { *ld.FlagTextAddr = 0x08048000 + int64(ld.HEADR) } if *ld.FlagDataAddr == -1 { *ld.FlagDataAddr = 0 } if *ld.FlagRound == -1 { *ld.FlagRound = 4096 } case obj.Hnacl: ld.Elfinit(ctxt) ld.HEADR = 0x10000 ld.Funcalign = 32 if *ld.FlagTextAddr == -1 { *ld.FlagTextAddr = 0x20000 } if *ld.FlagDataAddr == -1 { *ld.FlagDataAddr = 0 } if *ld.FlagRound == -1 { *ld.FlagRound = 0x10000 } case obj.Hwindows: /* PE executable */ ld.Peinit(ctxt) ld.HEADR = ld.PEFILEHEADR if *ld.FlagTextAddr == -1 { *ld.FlagTextAddr = ld.PEBASE + int64(ld.PESECTHEADR) } if *ld.FlagDataAddr == -1 { *ld.FlagDataAddr = 0 } if *ld.FlagRound == -1 { *ld.FlagRound = ld.PESECTALIGN } } if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 { fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound)) } }
func archinit() { // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" { ld.Linkmode = ld.LinkInternal } if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() { ld.Linkmode = ld.LinkExternal } switch ld.HEADTYPE { default: if ld.Linkmode == ld.LinkAuto { ld.Linkmode = ld.LinkInternal } if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" { log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE))) } case obj.Hdarwin, obj.Hdragonfly, obj.Hhaiku, obj.Hfreebsd, obj.Hlinux, obj.Hnacl, obj.Hnetbsd, obj.Hopenbsd, obj.Hsolaris, obj.Hwindows: break } switch ld.HEADTYPE { default: ld.Exitf("unknown -H option: %v", ld.HEADTYPE) case obj.Hplan9: /* plan 9 */ ld.HEADR = 32 + 8 if ld.INITTEXT == -1 { ld.INITTEXT = 0x200000 + int64(ld.HEADR) } if ld.INITDAT == -1 { ld.INITDAT = 0 } if ld.INITRND == -1 { ld.INITRND = 0x200000 } case obj.Helf: /* elf32 executable */ ld.HEADR = int32(ld.Rnd(52+3*32, 16)) if ld.INITTEXT == -1 { ld.INITTEXT = 0x80110000 } if ld.INITDAT == -1 { ld.INITDAT = 0 } if ld.INITRND == -1 { ld.INITRND = 4096 } case obj.Hdarwin: /* apple MACH */ ld.Machoinit() ld.HEADR = ld.INITIAL_MACHO_HEADR if ld.INITRND == -1 { ld.INITRND = 4096 } if ld.INITTEXT == -1 { ld.INITTEXT = 4096 + int64(ld.HEADR) } if ld.INITDAT == -1 { ld.INITDAT = 0 } case obj.Hlinux, /* elf64 executable */ obj.Hfreebsd, /* freebsd */ obj.Hhaiku, /* haiku */ obj.Hnetbsd, /* netbsd */ obj.Hopenbsd, /* openbsd */ obj.Hdragonfly, /* dragonfly */ obj.Hsolaris: /* solaris */ ld.Elfinit() ld.HEADR = ld.ELFRESERVE if ld.INITTEXT == -1 { ld.INITTEXT = (1 << 22) + int64(ld.HEADR) } if ld.INITDAT == -1 { ld.INITDAT = 0 } if ld.INITRND == -1 { ld.INITRND = 4096 } case obj.Hnacl: ld.Elfinit() ld.Debug['w']++ // disable dwarf, which gets confused and is useless anyway ld.HEADR = 0x10000 ld.Funcalign = 32 if ld.INITTEXT == -1 { ld.INITTEXT = 0x20000 } if ld.INITDAT == -1 { ld.INITDAT = 0 } if ld.INITRND == -1 { ld.INITRND = 0x10000 } case obj.Hwindows: /* PE executable */ ld.Peinit() ld.HEADR = ld.PEFILEHEADR if ld.INITTEXT == -1 { ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR) } if ld.INITDAT == -1 { ld.INITDAT = 0 } if ld.INITRND == -1 { ld.INITRND = ld.PESECTALIGN } } if ld.INITDAT != 0 && ld.INITRND != 0 { fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND)) } }
func archinit(ctxt *ld.Link) { // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" { ld.Linkmode = ld.LinkInternal } // Darwin/arm64 only supports external linking if ld.HEADTYPE == obj.Hdarwin { ld.Linkmode = ld.LinkExternal } switch ld.HEADTYPE { default: if ld.Linkmode == ld.LinkAuto { ld.Linkmode = ld.LinkInternal } if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" { log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE))) } case obj.Hlinux, obj.Hdarwin: break } if ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() { ld.Linkmode = ld.LinkExternal } switch ld.HEADTYPE { default: ld.Exitf("unknown -H option: %v", ld.HEADTYPE) case obj.Hplan9: /* plan 9 */ ld.HEADR = 32 if *ld.FlagTextAddr == -1 { *ld.FlagTextAddr = 4128 } if *ld.FlagDataAddr == -1 { *ld.FlagDataAddr = 0 } if *ld.FlagRound == -1 { *ld.FlagRound = 4096 } case obj.Hlinux: /* arm64 elf */ ld.Elfinit(ctxt) ld.HEADR = ld.ELFRESERVE if *ld.FlagTextAddr == -1 { *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR) } if *ld.FlagDataAddr == -1 { *ld.FlagDataAddr = 0 } if *ld.FlagRound == -1 { *ld.FlagRound = 0x10000 } case obj.Hdarwin: /* apple MACH */ *ld.FlagW = true // disable DWARF generation ld.Machoinit() ld.HEADR = ld.INITIAL_MACHO_HEADR if *ld.FlagTextAddr == -1 { *ld.FlagTextAddr = 4096 + int64(ld.HEADR) } if *ld.FlagDataAddr == -1 { *ld.FlagDataAddr = 0 } if *ld.FlagRound == -1 { *ld.FlagRound = 4096 } case obj.Hnacl: ld.Elfinit(ctxt) ld.HEADR = 0x10000 ld.Funcalign = 16 if *ld.FlagTextAddr == -1 { *ld.FlagTextAddr = 0x20000 } if *ld.FlagDataAddr == -1 { *ld.FlagDataAddr = 0 } if *ld.FlagRound == -1 { *ld.FlagRound = 0x10000 } } if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 { fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound)) } }