diff options
Diffstat (limited to 'src/cmd/link/internal/amd64/asm.go')
-rw-r--r-- | src/cmd/link/internal/amd64/asm.go | 184 |
1 files changed, 99 insertions, 85 deletions
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index 26208cc619..cb1210422d 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -34,9 +34,11 @@ import ( "cmd/internal/objabi" "cmd/internal/sys" "cmd/link/internal/ld" + "cmd/link/internal/loader" "cmd/link/internal/sym" "debug/elf" "log" + "sync" ) func PADDR(x uint32) uint32 { @@ -98,13 +100,21 @@ func gentext(ctxt *ld.Link) { initarray_entry.AddAddr(ctxt.Arch, initfunc) } -func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { +// makeWritable makes a readonly symbol writable if we do opcode rewriting. +func makeWritable(s *sym.Symbol) { + if s.Attr.ReadOnly() { + s.Attr.Set(sym.AttrReadOnly, false) + s.P = append([]byte(nil), s.P...) + } +} + +func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool { targ := r.Sym switch r.Type { default: if r.Type >= objabi.ElfRelocOffset { - ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type)) + ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type)) return false } @@ -137,8 +147,8 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { r.Type = objabi.R_PCREL r.Add += 4 if targ.Type == sym.SDYNIMPORT { - addpltsym(ctxt, targ) - r.Sym = ctxt.Syms.Lookup(".plt", 0) + addpltsym(target, syms, targ) + r.Sym = syms.PLT r.Add += int64(targ.Plt()) } @@ -150,6 +160,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type != sym.SDYNIMPORT { // have symbol if r.Off >= 2 && s.P[r.Off-2] == 0x8b { + makeWritable(s) // turn MOVQ of GOT entry into LEAQ of symbol itself s.P[r.Off-2] = 0x8d @@ -161,10 +172,10 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { // fall back to using GOT and hope for the best (CMOV*) // TODO: just needs relocation, no need to put in .dynsym - addgotsym(ctxt, targ) + addgotsym(target, syms, targ) r.Type = objabi.R_PCREL - r.Sym = ctxt.Syms.Lookup(".got", 0) + r.Sym = syms.GOT r.Add += 4 r.Add += int64(targ.Got()) return true @@ -174,7 +185,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name) } r.Type = objabi.R_ADDR - if ctxt.BuildMode == ld.BuildModePIE && ctxt.LinkMode == ld.LinkInternal { + if target.IsPIE() && target.IsInternal() { // For internal linking PIE, this R_ADDR relocation cannot // be resolved statically. We need to generate a dynamic // relocation. Let the code below handle it. @@ -196,8 +207,8 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1: if targ.Type == sym.SDYNIMPORT { - addpltsym(ctxt, targ) - r.Sym = ctxt.Syms.Lookup(".plt", 0) + addpltsym(target, syms, targ) + r.Sym = syms.PLT r.Add = int64(targ.Plt()) r.Type = objabi.R_PCREL return true @@ -225,6 +236,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { return false } + makeWritable(s) s.P[r.Off-2] = 0x8d r.Type = objabi.R_PCREL return true @@ -235,9 +247,9 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type != sym.SDYNIMPORT { ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name) } - addgotsym(ctxt, targ) + addgotsym(target, syms, targ) r.Type = objabi.R_PCREL - r.Sym = ctxt.Syms.Lookup(".got", 0) + r.Sym = syms.GOT r.Add += int64(targ.Got()) return true } @@ -249,37 +261,37 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { // nothing to do, the relocation will be laid out in reloc return true } - if ctxt.LinkMode == ld.LinkExternal { + if target.IsExternal() { // External linker will do this relocation. return true } // Internal linking, for both ELF and Mach-O. // Build a PLT entry and change the relocation target to that entry. - addpltsym(ctxt, targ) - r.Sym = ctxt.Syms.Lookup(".plt", 0) + addpltsym(target, syms, targ) + r.Sym = syms.PLT r.Add = int64(targ.Plt()) return true case objabi.R_ADDR: - if s.Type == sym.STEXT && ctxt.IsELF { - if ctxt.HeadType == objabi.Hsolaris { - addpltsym(ctxt, targ) - r.Sym = ctxt.Syms.Lookup(".plt", 0) + if s.Type == sym.STEXT && target.IsElf() { + if target.IsSolaris() { + addpltsym(target, syms, targ) + r.Sym = syms.PLT r.Add += int64(targ.Plt()) return true } // The code is asking for the address of an external // function. We provide it with the address of the // correspondent GOT symbol. - addgotsym(ctxt, targ) + addgotsym(target, syms, targ) - r.Sym = ctxt.Syms.Lookup(".got", 0) + r.Sym = syms.GOT r.Add += int64(targ.Got()) return true } // Process dynamic relocations for the data sections. - if ctxt.BuildMode == ld.BuildModePIE && ctxt.LinkMode == ld.LinkInternal { + if target.IsPIE() && target.IsInternal() { // When internally linking, generate dynamic relocations // for all typical R_ADDR relocations. The exception // are those R_ADDR that are created as part of generating @@ -327,7 +339,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { } } - if ctxt.IsELF { + if target.IsElf() { // Generate R_X86_64_RELATIVE relocations for best // efficiency in the dynamic linker. // @@ -345,14 +357,14 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { // AddAddrPlus is used for r_offset and r_addend to // generate new R_ADDR relocations that will update // these fields in the 'reloc' phase. - rela := ctxt.Syms.Lookup(".rela", 0) - rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off)) + rela := syms.Rela + rela.AddAddrPlus(target.Arch, s, int64(r.Off)) if r.Siz == 8 { - rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE))) + rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE))) } else { ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) } - rela.AddAddrPlus(ctxt.Arch, targ, int64(r.Add)) + rela.AddAddrPlus(target.Arch, targ, int64(r.Add)) // Not mark r done here. So we still apply it statically, // so in the file content we'll also have the right offset // to the relocation target. So it can be examined statically @@ -360,7 +372,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { return true } - if ctxt.HeadType == objabi.Hdarwin && s.Size == int64(ctxt.Arch.PtrSize) && r.Off == 0 { + if target.IsDarwin() && s.Size == int64(target.Arch.PtrSize) && r.Off == 0 { // Mach-O relocations are a royal pain to lay out. // They use a compact stateful bytecode representation // that is too much bother to deal with. @@ -371,17 +383,17 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { // just in case the C code assigns to the variable, // and of course it only works for single pointers, // but we only need to support cgo and that's all it needs. - ld.Adddynsym(ctxt, targ) + ld.Adddynsym(target, syms, targ) - got := ctxt.Syms.Lookup(".got", 0) + got := syms.GOT s.Type = got.Type s.Attr |= sym.AttrSubSymbol s.Outer = got s.Sub = got.Sub got.Sub = s s.Value = got.Size - got.AddUint64(ctxt.Arch, 0) - ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(targ.Dynid)) + got.AddUint64(target.Arch, 0) + syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid)) r.Type = objabi.ElfRelocOffset // ignore during relocsym return true } @@ -553,84 +565,82 @@ func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, secto return true } -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { +func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { return val, false } -func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { +func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 { log.Fatalf("unexpected relocation variant") return t } -func elfsetupplt(ctxt *ld.Link) { - plt := ctxt.Syms.Lookup(".plt", 0) - got := ctxt.Syms.Lookup(".got.plt", 0) - if plt.Size == 0 { +func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) { + if plt.Size() == 0 { // pushq got+8(IP) plt.AddUint8(0xff) plt.AddUint8(0x35) - plt.AddPCRelPlus(ctxt.Arch, got, 8) + plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 8) // jmpq got+16(IP) plt.AddUint8(0xff) plt.AddUint8(0x25) - plt.AddPCRelPlus(ctxt.Arch, got, 16) + plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 16) // nopl 0(AX) plt.AddUint32(ctxt.Arch, 0x00401f0f) // assume got->size == 0 too - got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0) + got.AddAddrPlus(ctxt.Arch, dynamic, 0) got.AddUint64(ctxt.Arch, 0) got.AddUint64(ctxt.Arch, 0) } } -func addpltsym(ctxt *ld.Link, s *sym.Symbol) { +func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) { if s.Plt() >= 0 { return } - ld.Adddynsym(ctxt, s) + ld.Adddynsym(target, syms, s) - if ctxt.IsELF { - plt := ctxt.Syms.Lookup(".plt", 0) - got := ctxt.Syms.Lookup(".got.plt", 0) - rela := ctxt.Syms.Lookup(".rela.plt", 0) + if target.IsElf() { + plt := syms.PLT + got := syms.GOTPLT + rela := syms.RelaPLT if plt.Size == 0 { - elfsetupplt(ctxt) + panic("plt is not set up") } // jmpq *got+size(IP) plt.AddUint8(0xff) plt.AddUint8(0x25) - plt.AddPCRelPlus(ctxt.Arch, got, got.Size) + plt.AddPCRelPlus(target.Arch, got, got.Size) // add to got: pointer to current pos in plt - got.AddAddrPlus(ctxt.Arch, plt, plt.Size) + got.AddAddrPlus(target.Arch, plt, plt.Size) // pushq $x plt.AddUint8(0x68) - plt.AddUint32(ctxt.Arch, uint32((got.Size-24-8)/8)) + plt.AddUint32(target.Arch, uint32((got.Size-24-8)/8)) // jmpq .plt plt.AddUint8(0xe9) - plt.AddUint32(ctxt.Arch, uint32(-(plt.Size + 4))) + plt.AddUint32(target.Arch, uint32(-(plt.Size + 4))) // rela - rela.AddAddrPlus(ctxt.Arch, got, got.Size-8) + rela.AddAddrPlus(target.Arch, got, got.Size-8) - rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT))) - rela.AddUint64(ctxt.Arch, 0) + rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT))) + rela.AddUint64(target.Arch, 0) s.SetPlt(int32(plt.Size - 16)) - } else if ctxt.HeadType == objabi.Hdarwin { + } else if target.IsDarwin() { // To do lazy symbol lookup right, we're supposed // to tell the dynamic loader which library each // symbol comes from and format the link info @@ -641,39 +651,39 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { // https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html // has details about what we're avoiding. - addgotsym(ctxt, s) - plt := ctxt.Syms.Lookup(".plt", 0) + addgotsym(target, syms, s) + plt := syms.PLT - ctxt.Syms.Lookup(".linkedit.plt", 0).AddUint32(ctxt.Arch, uint32(s.Dynid)) + syms.LinkEditPLT.AddUint32(target.Arch, uint32(s.Dynid)) // jmpq *got+size(IP) s.SetPlt(int32(plt.Size)) plt.AddUint8(0xff) plt.AddUint8(0x25) - plt.AddPCRelPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got())) + plt.AddPCRelPlus(target.Arch, syms.GOT, int64(s.Got())) } else { ld.Errorf(s, "addpltsym: unsupported binary format") } } -func addgotsym(ctxt *ld.Link, s *sym.Symbol) { +func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) { if s.Got() >= 0 { return } - ld.Adddynsym(ctxt, s) - got := ctxt.Syms.Lookup(".got", 0) + ld.Adddynsym(target, syms, s) + got := syms.GOT s.SetGot(int32(got.Size)) - got.AddUint64(ctxt.Arch, 0) - - if ctxt.IsELF { - rela := ctxt.Syms.Lookup(".rela", 0) - rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got())) - rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT))) - rela.AddUint64(ctxt.Arch, 0) - } else if ctxt.HeadType == objabi.Hdarwin { - ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(s.Dynid)) + got.AddUint64(target.Arch, 0) + + if target.IsElf() { + rela := syms.Rela + rela.AddAddrPlus(target.Arch, got, int64(s.Got())) + rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT))) + rela.AddUint64(target.Arch, 0) + } else if target.IsDarwin() { + syms.LinkEditGOT.AddUint32(target.Arch, uint32(s.Dynid)) } else { ld.Errorf(s, "addgotsym: unsupported binary format") } @@ -684,29 +694,33 @@ func asmb(ctxt *ld.Link) { ld.Asmbelfsetup() } + var wg sync.WaitGroup sect := ld.Segtext.Sections[0] - ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - // 0xCC is INT $3 - breakpoint instruction - ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC}) - for _, sect = range ld.Segtext.Sections[1:] { - ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length)) + offset := sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff + f := func(ctxt *ld.Link, out *ld.OutBuf, start, length int64) { + // 0xCC is INT $3 - breakpoint instruction + ld.CodeblkPad(ctxt, out, start, length, []byte{0xCC}) + } + ld.WriteParallel(&wg, f, ctxt, offset, sect.Vaddr, sect.Length) + + for _, sect := range ld.Segtext.Sections[1:] { + offset := sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff + ld.WriteParallel(&wg, ld.Datblk, ctxt, offset, sect.Vaddr, sect.Length) } if ld.Segrodata.Filelen > 0 { - ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen)) + ld.WriteParallel(&wg, ld.Datblk, ctxt, ld.Segrodata.Fileoff, ld.Segrodata.Vaddr, ld.Segrodata.Filelen) } + if ld.Segrelrodata.Filelen > 0 { - ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen)) + ld.WriteParallel(&wg, ld.Datblk, ctxt, ld.Segrelrodata.Fileoff, ld.Segrelrodata.Vaddr, ld.Segrelrodata.Filelen) } - ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff)) - ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) + ld.WriteParallel(&wg, ld.Datblk, ctxt, ld.Segdata.Fileoff, ld.Segdata.Vaddr, ld.Segdata.Filelen) + + ld.WriteParallel(&wg, ld.Dwarfblk, ctxt, ld.Segdwarf.Fileoff, ld.Segdwarf.Vaddr, ld.Segdwarf.Filelen) - ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff)) - ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) + wg.Wait() } func asmb2(ctxt *ld.Link) { |