From dca5f2e9b3212ef6df7e08ebd818b804ad27db91 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sat, 28 Feb 2015 13:48:09 -0500 Subject: [PATCH] cmd/5l etc: replace C code with Go code mv cmd/new5l cmd/5l and so on. Minimal changes to cmd/dist and cmd/go to keep things building. More can be deleted in followup CLs. Change-Id: I1449eca7654ce2580d1f413a56dc4a75f3d4618b Reviewed-on: https://go-review.googlesource.com/6361 Reviewed-by: Rob Pike --- src/cmd/5l/Makefile | 5 - src/cmd/5l/asm.c | 749 --------- src/cmd/{new5l => 5l}/asm.go | 0 src/cmd/5l/doc.go | 15 - src/cmd/{new5l => 5l}/l.go | 0 src/cmd/5l/l.h | 66 - src/cmd/5l/obj.c | 167 -- src/cmd/{new5l => 5l}/obj.go | 0 src/cmd/6l/Makefile | 5 - src/cmd/6l/asm.c | 795 --------- src/cmd/{new6l => 6l}/asm.go | 0 src/cmd/6l/doc.go | 15 - src/cmd/{new6l => 6l}/l.go | 0 src/cmd/6l/l.h | 67 - src/cmd/6l/obj.c | 191 --- src/cmd/{new6l => 6l}/obj.go | 0 src/cmd/{new6l => 6l}/z.go | 0 src/cmd/8l/Makefile | 5 - src/cmd/8l/asm.c | 707 -------- src/cmd/{new8l => 8l}/asm.go | 0 src/cmd/8l/doc.go | 15 - src/cmd/{new8l => 8l}/l.go | 0 src/cmd/8l/l.h | 66 - src/cmd/8l/obj.c | 175 -- src/cmd/{new8l => 8l}/obj.go | 0 src/cmd/9l/Makefile | 5 - src/cmd/9l/asm.c | 814 --------- src/cmd/{new9l => 9l}/asm.go | 0 src/cmd/9l/doc.go | 16 - src/cmd/{new9l => 9l}/l.go | 0 src/cmd/9l/l.h | 65 - src/cmd/9l/obj.c | 151 -- src/cmd/{new9l => 9l}/obj.go | 0 src/cmd/dist/build.go | 57 +- src/cmd/dist/buildtool.go | 8 +- src/cmd/go/build.go | 2 +- src/cmd/go/pkg.go | 8 +- src/cmd/ld/Makefile | 5 - src/cmd/ld/data.c | 1460 ---------------- src/cmd/ld/decodesym.c | 251 --- src/cmd/ld/doc.go | 100 -- src/cmd/ld/dwarf.c | 2498 ---------------------------- src/cmd/ld/dwarf.h | 25 - src/cmd/ld/dwarf_defs.h | 504 ------ src/cmd/ld/elf.c | 1685 ------------------- src/cmd/ld/elf.h | 857 ---------- src/cmd/ld/go.c | 864 ---------- src/cmd/ld/ldelf.c | 958 ----------- src/cmd/ld/ldmacho.c | 853 ---------- src/cmd/ld/ldpe.c | 504 ------ src/cmd/ld/lib.c | 1636 ------------------ src/cmd/ld/lib.h | 328 ---- src/cmd/ld/macho.c | 785 --------- src/cmd/ld/macho.h | 98 -- src/cmd/ld/pcln.c | 347 ---- src/cmd/ld/pe.c | 759 --------- src/cmd/ld/pe.h | 189 --- src/cmd/ld/pobj.c | 198 --- src/cmd/ld/symtab.c | 449 ----- src/{cmd/ld => runtime}/textflag.h | 13 - 60 files changed, 11 insertions(+), 19524 deletions(-) delete mode 100644 src/cmd/5l/Makefile delete mode 100644 src/cmd/5l/asm.c rename src/cmd/{new5l => 5l}/asm.go (100%) delete mode 100644 src/cmd/5l/doc.go rename src/cmd/{new5l => 5l}/l.go (100%) delete mode 100644 src/cmd/5l/l.h delete mode 100644 src/cmd/5l/obj.c rename src/cmd/{new5l => 5l}/obj.go (100%) delete mode 100644 src/cmd/6l/Makefile delete mode 100644 src/cmd/6l/asm.c rename src/cmd/{new6l => 6l}/asm.go (100%) delete mode 100644 src/cmd/6l/doc.go rename src/cmd/{new6l => 6l}/l.go (100%) delete mode 100644 src/cmd/6l/l.h delete mode 100644 src/cmd/6l/obj.c rename src/cmd/{new6l => 6l}/obj.go (100%) rename src/cmd/{new6l => 6l}/z.go (100%) delete mode 100644 src/cmd/8l/Makefile delete mode 100644 src/cmd/8l/asm.c rename src/cmd/{new8l => 8l}/asm.go (100%) delete mode 100644 src/cmd/8l/doc.go rename src/cmd/{new8l => 8l}/l.go (100%) delete mode 100644 src/cmd/8l/l.h delete mode 100644 src/cmd/8l/obj.c rename src/cmd/{new8l => 8l}/obj.go (100%) delete mode 100644 src/cmd/9l/Makefile delete mode 100644 src/cmd/9l/asm.c rename src/cmd/{new9l => 9l}/asm.go (100%) delete mode 100644 src/cmd/9l/doc.go rename src/cmd/{new9l => 9l}/l.go (100%) delete mode 100644 src/cmd/9l/l.h delete mode 100644 src/cmd/9l/obj.c rename src/cmd/{new9l => 9l}/obj.go (100%) delete mode 100644 src/cmd/ld/Makefile delete mode 100644 src/cmd/ld/data.c delete mode 100644 src/cmd/ld/decodesym.c delete mode 100644 src/cmd/ld/doc.go delete mode 100644 src/cmd/ld/dwarf.c delete mode 100644 src/cmd/ld/dwarf.h delete mode 100644 src/cmd/ld/dwarf_defs.h delete mode 100644 src/cmd/ld/elf.c delete mode 100644 src/cmd/ld/elf.h delete mode 100644 src/cmd/ld/go.c delete mode 100644 src/cmd/ld/ldelf.c delete mode 100644 src/cmd/ld/ldmacho.c delete mode 100644 src/cmd/ld/ldpe.c delete mode 100644 src/cmd/ld/lib.c delete mode 100644 src/cmd/ld/lib.h delete mode 100644 src/cmd/ld/macho.c delete mode 100644 src/cmd/ld/macho.h delete mode 100644 src/cmd/ld/pcln.c delete mode 100644 src/cmd/ld/pe.c delete mode 100644 src/cmd/ld/pe.h delete mode 100644 src/cmd/ld/pobj.c delete mode 100644 src/cmd/ld/symtab.c rename src/{cmd/ld => runtime}/textflag.h (87%) diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile deleted file mode 100644 index 3f528d7517..0000000000 --- a/src/cmd/5l/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c deleted file mode 100644 index 079c973da4..0000000000 --- a/src/cmd/5l/asm.c +++ /dev/null @@ -1,749 +0,0 @@ -// Inferno utils/5l/asm.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Writing object files. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" -#include "../ld/macho.h" -#include "../ld/dwarf.h" - -static int -needlib(char *name) -{ - char *p; - LSym *s; - - if(*name == '\0') - return 0; - - /* reuse hash code in symbol table */ - p = smprint(".dynlib.%s", name); - s = linklookup(ctxt, p, 0); - free(p); - if(s->type == 0) { - s->type = 100; // avoid SDATA, etc. - return 1; - } - return 0; -} - -static void addpltsym(Link*, LSym*); -static void addgotsym(Link*, LSym*); -static void addgotsyminternal(Link*, LSym*); - -void -gentext(void) -{ -} - -// Preserve highest 8 bits of a, and do addition to lower 24-bit -// of a and b; used to adjust ARM branch intruction's target -static int32 -braddoff(int32 a, int32 b) -{ - return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b)); -} - -void -adddynrela(LSym *rel, LSym *s, Reloc *r) -{ - addaddrplus(ctxt, rel, s, r->off); - adduint32(ctxt, rel, R_ARM_RELATIVE); -} - -void -adddynrel(LSym *s, Reloc *r) -{ - LSym *targ, *rel; - - targ = r->sym; - ctxt->cursym = s; - - switch(r->type) { - default: - if(r->type >= 256) { - diag("unexpected relocation type %d", r->type); - return; - } - break; - - // Handle relocations found in ELF object files. - case 256 + R_ARM_PLT32: - r->type = R_CALLARM; - if(targ->type == SDYNIMPORT) { - addpltsym(ctxt, targ); - r->sym = linklookup(ctxt, ".plt", 0); - r->add = braddoff(r->add, targ->plt / 4); - } - return; - - case 256 + R_ARM_THM_PC22: // R_ARM_THM_CALL - diag("R_ARM_THM_CALL, are you using -marm?"); - errorexit(); - return; - - case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL - if(targ->type != SDYNIMPORT) { - addgotsyminternal(ctxt, targ); - } else { - addgotsym(ctxt, targ); - } - r->type = R_CONST; // write r->add during relocsym - r->sym = nil; - r->add += targ->got; - return; - - case 256 + R_ARM_GOT_PREL: // GOT(nil) + A - nil - if(targ->type != SDYNIMPORT) { - addgotsyminternal(ctxt, targ); - } else { - addgotsym(ctxt, targ); - } - r->type = R_PCREL; - r->sym = linklookup(ctxt, ".got", 0); - r->add += targ->got + 4; - return; - - case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32 - r->type = R_GOTOFF; - return; - - case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL - r->type = R_PCREL; - r->sym = linklookup(ctxt, ".got", 0); - r->add += 4; - return; - - case 256 + R_ARM_CALL: - r->type = R_CALLARM; - if(targ->type == SDYNIMPORT) { - addpltsym(ctxt, targ); - r->sym = linklookup(ctxt, ".plt", 0); - r->add = braddoff(r->add, targ->plt / 4); - } - return; - - case 256 + R_ARM_REL32: // R_ARM_REL32 - r->type = R_PCREL; - r->add += 4; - return; - - case 256 + R_ARM_ABS32: - if(targ->type == SDYNIMPORT) - diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name); - r->type = R_ADDR; - return; - - case 256 + R_ARM_V4BX: - // we can just ignore this, because we are targeting ARM V5+ anyway - if(r->sym) { - // R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it - r->sym->type = 0; - } - r->sym = nil; - return; - - case 256 + R_ARM_PC24: - case 256 + R_ARM_JUMP24: - r->type = R_CALLARM; - if(targ->type == SDYNIMPORT) { - addpltsym(ctxt, targ); - r->sym = linklookup(ctxt, ".plt", 0); - r->add = braddoff(r->add, targ->plt / 4); - } - return; - } - - // Handle references to ELF symbols from our own object files. - if(targ->type != SDYNIMPORT) - return; - - switch(r->type) { - case R_CALLARM: - addpltsym(ctxt, targ); - r->sym = linklookup(ctxt, ".plt", 0); - r->add = targ->plt; - return; - - case R_ADDR: - if(s->type != SDATA) - break; - if(iself) { - adddynsym(ctxt, targ); - rel = linklookup(ctxt, ".rel", 0); - addaddrplus(ctxt, rel, s, r->off); - adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a nil + A dynmic reloc - r->type = R_CONST; // write r->add during relocsym - r->sym = nil; - return; - } - break; - } - - ctxt->cursym = s; - diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); -} - -int -elfreloc1(Reloc *r, vlong sectoff) -{ - int32 elfsym; - - thearch.lput(sectoff); - - elfsym = r->xsym->elfsym; - switch(r->type) { - default: - return -1; - - case R_ADDR: - if(r->siz == 4) - thearch.lput(R_ARM_ABS32 | elfsym<<8); - else - return -1; - break; - - case R_PCREL: - if(r->siz == 4) - thearch.lput(R_ARM_REL32 | elfsym<<8); - else - return -1; - break; - - case R_CALLARM: - if(r->siz == 4) { - if((r->add & 0xff000000) == 0xeb000000) // BL - thearch.lput(R_ARM_CALL | elfsym<<8); - else - thearch.lput(R_ARM_JUMP24 | elfsym<<8); - } else - return -1; - break; - - case R_TLS: - if(r->siz == 4) { - if(flag_shared) - thearch.lput(R_ARM_TLS_IE32 | elfsym<<8); - else - thearch.lput(R_ARM_TLS_LE32 | elfsym<<8); - } else - return -1; - break; - } - - return 0; -} - -void -elfsetupplt(void) -{ - LSym *plt, *got; - - plt = linklookup(ctxt, ".plt", 0); - got = linklookup(ctxt, ".got.plt", 0); - if(plt->size == 0) { - // str lr, [sp, #-4]! - adduint32(ctxt, plt, 0xe52de004); - // ldr lr, [pc, #4] - adduint32(ctxt, plt, 0xe59fe004); - // add lr, pc, lr - adduint32(ctxt, plt, 0xe08fe00e); - // ldr pc, [lr, #8]! - adduint32(ctxt, plt, 0xe5bef008); - // .word &GLOBAL_OFFSET_TABLE[0] - . - addpcrelplus(ctxt, plt, got, 4); - - // the first .plt entry requires 3 .plt.got entries - adduint32(ctxt, got, 0); - adduint32(ctxt, got, 0); - adduint32(ctxt, got, 0); - } -} - -int -machoreloc1(Reloc *r, vlong sectoff) -{ - uint32 v; - LSym *rs; - - rs = r->xsym; - - if(rs->type == SHOSTOBJ || r->type == R_CALLARM) { - if(rs->dynid < 0) { - diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type); - return -1; - } - v = rs->dynid; - v |= 1<<27; // external relocation - } else { - v = ((Section*)rs->sect)->extnum; - if(v == 0) { - diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, ((Section*)rs->sect)->name, rs->type); - return -1; - } - } - - switch(r->type) { - default: - return -1; - case R_ADDR: - v |= MACHO_GENERIC_RELOC_VANILLA<<28; - break; - case R_CALLARM: - v |= 1<<24; // pc-relative bit - v |= MACHO_ARM_RELOC_BR24<<28; - break; - } - - switch(r->siz) { - default: - return -1; - case 1: - v |= 0<<25; - break; - case 2: - v |= 1<<25; - break; - case 4: - v |= 2<<25; - break; - case 8: - v |= 3<<25; - break; - } - - thearch.lput(sectoff); - thearch.lput(v); - return 0; -} - - -int -archreloc(Reloc *r, LSym *s, vlong *val) -{ - LSym *rs; - - if(linkmode == LinkExternal) { - switch(r->type) { - case R_CALLARM: - r->done = 0; - - // set up addend for eventual relocation via outer symbol. - rs = r->sym; - r->xadd = r->add; - if(r->xadd & 0x800000) - r->xadd |= ~0xffffff; - r->xadd *= 4; - while(rs->outer != nil) { - r->xadd += symaddr(rs) - symaddr(rs->outer); - rs = rs->outer; - } - - if(rs->type != SHOSTOBJ && rs->sect == nil) - diag("missing section for %s", rs->name); - r->xsym = rs; - - // ld64 for arm seems to want the symbol table to contain offset - // into the section rather than pseudo virtual address that contains - // the section load address. - // we need to compensate that by removing the instruction's address - // from addend. - if(HEADTYPE == Hdarwin) - r->xadd -= symaddr(s) + r->off; - - *val = braddoff((0xff000000U & (uint32)r->add), - (0xffffff & (uint32)(r->xadd / 4))); - return 0; - } - return -1; - } - switch(r->type) { - case R_CONST: - *val = r->add; - return 0; - case R_GOTOFF: - *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); - return 0; - // The following three arch specific relocations are only for generation of - // Linux/ARM ELF's PLT entry (3 assembler instruction) - case R_PLT0: // add ip, pc, #0xXX00000 - if (symaddr(linklookup(ctxt, ".got.plt", 0)) < symaddr(linklookup(ctxt, ".plt", 0))) - diag(".got.plt should be placed after .plt section."); - *val = 0xe28fc600U + - (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add) >> 20)); - return 0; - case R_PLT1: // add ip, ip, #0xYY000 - *val = 0xe28cca00U + - (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 4) >> 12)); - return 0; - case R_PLT2: // ldr pc, [ip, #0xZZZ]! - *val = 0xe5bcf000U + - (0xfff & (uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 8)); - return 0; - case R_CALLARM: // bl XXXXXX or b YYYYYY - *val = braddoff((0xff000000U & (uint32)r->add), - (0xffffff & (uint32) - ((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4))); - return 0; - } - return -1; -} - -vlong -archrelocvariant(Reloc *r, LSym *s, vlong t) -{ - USED(r); - USED(s); - sysfatal("unexpected relocation variant"); - return t; -} - -static Reloc * -addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ) -{ - Reloc *r; - - r = addrel(plt); - r->sym = got; - r->off = plt->size; - r->siz = 4; - r->type = typ; - r->add = sym->got - 8; - - plt->reachable = 1; - plt->size += 4; - symgrow(ctxt, plt, plt->size); - - return r; -} - -static void -addpltsym(Link *ctxt, LSym *s) -{ - LSym *plt, *got, *rel; - - if(s->plt >= 0) - return; - - adddynsym(ctxt, s); - - if(iself) { - plt = linklookup(ctxt, ".plt", 0); - got = linklookup(ctxt, ".got.plt", 0); - rel = linklookup(ctxt, ".rel.plt", 0); - if(plt->size == 0) - elfsetupplt(); - - // .got entry - s->got = got->size; - // In theory, all GOT should point to the first PLT entry, - // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's - // dynamic linker won't, so we'd better do it ourselves. - addaddrplus(ctxt, got, plt, 0); - - // .plt entry, this depends on the .got entry - s->plt = plt->size; - addpltreloc(ctxt, plt, got, s, R_PLT0); // add lr, pc, #0xXX00000 - addpltreloc(ctxt, plt, got, s, R_PLT1); // add lr, lr, #0xYY000 - addpltreloc(ctxt, plt, got, s, R_PLT2); // ldr pc, [lr, #0xZZZ]! - - // rel - addaddrplus(ctxt, rel, got, s->got); - adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT)); - } else { - diag("addpltsym: unsupported binary format"); - } -} - -static void -addgotsyminternal(Link *ctxt, LSym *s) -{ - LSym *got; - - if(s->got >= 0) - return; - - got = linklookup(ctxt, ".got", 0); - s->got = got->size; - - addaddrplus(ctxt, got, s, 0); - - if(iself) { - ; - } else { - diag("addgotsyminternal: unsupported binary format"); - } -} - -static void -addgotsym(Link *ctxt, LSym *s) -{ - LSym *got, *rel; - - if(s->got >= 0) - return; - - adddynsym(ctxt, s); - got = linklookup(ctxt, ".got", 0); - s->got = got->size; - adduint32(ctxt, got, 0); - - if(iself) { - rel = linklookup(ctxt, ".rel", 0); - addaddrplus(ctxt, rel, got, s->got); - adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT)); - } else { - diag("addgotsym: unsupported binary format"); - } -} - -void -adddynsym(Link *ctxt, LSym *s) -{ - LSym *d; - int t; - char *name; - - if(s->dynid >= 0) - return; - - if(iself) { - s->dynid = nelfsym++; - - d = linklookup(ctxt, ".dynsym", 0); - - /* name */ - name = s->extname; - adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); - - /* value */ - if(s->type == SDYNIMPORT) - adduint32(ctxt, d, 0); - else - addaddr(ctxt, d, s); - - /* size */ - adduint32(ctxt, d, 0); - - /* type */ - t = STB_GLOBAL << 4; - if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT) - t |= STT_FUNC; - else - t |= STT_OBJECT; - adduint8(ctxt, d, t); - adduint8(ctxt, d, 0); - - /* shndx */ - if(s->type == SDYNIMPORT) - adduint16(ctxt, d, SHN_UNDEF); - else - adduint16(ctxt, d, 1); - } else { - diag("adddynsym: unsupported binary format"); - } -} - -void -adddynlib(char *lib) -{ - LSym *s; - - if(!needlib(lib)) - return; - - if(iself) { - s = linklookup(ctxt, ".dynstr", 0); - if(s->size == 0) - addstring(s, ""); - elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); - } else if(HEADTYPE == Hdarwin) { - machoadddynlib(lib); - } else { - diag("adddynlib: unsupported binary format"); - } -} - -void -asmb(void) -{ - uint32 symo, dwarfoff, machlink; - Section *sect; - LSym *sym; - int i; - - if(debug['v']) - Bprint(&bso, "%5.2f asmb\n", cputime()); - Bflush(&bso); - - if(iself) - asmbelfsetup(); - - sect = segtext.sect; - cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); - codeblk(sect->vaddr, sect->length); - for(sect = sect->next; sect != nil; sect = sect->next) { - cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); - datblk(sect->vaddr, sect->length); - } - - if(segrodata.filelen > 0) { - if(debug['v']) - Bprint(&bso, "%5.2f rodatblk\n", cputime()); - Bflush(&bso); - - cseek(segrodata.fileoff); - datblk(segrodata.vaddr, segrodata.filelen); - } - - if(debug['v']) - Bprint(&bso, "%5.2f datblk\n", cputime()); - Bflush(&bso); - - cseek(segdata.fileoff); - datblk(segdata.vaddr, segdata.filelen); - - machlink = 0; - if(HEADTYPE == Hdarwin) { - if(debug['v']) - Bprint(&bso, "%5.2f dwarf\n", cputime()); - - if(!debug['w']) { // TODO(minux): enable DWARF Support - dwarfoff = rnd(HEADR+segtext.length, INITRND) + rnd(segdata.filelen, INITRND); - cseek(dwarfoff); - - segdwarf.fileoff = cpos(); - dwarfemitdebugsections(); - segdwarf.filelen = cpos() - segdwarf.fileoff; - } - machlink = domacholink(); - } - - /* output symbol table */ - symsize = 0; - lcsize = 0; - symo = 0; - if(!debug['s']) { - // TODO: rationalize - if(debug['v']) - Bprint(&bso, "%5.2f sym\n", cputime()); - Bflush(&bso); - switch(HEADTYPE) { - default: - if(iself) { - symo = segdata.fileoff+segdata.filelen; - symo = rnd(symo, INITRND); - } - break; - case Hplan9: - symo = segdata.fileoff+segdata.filelen; - break; - case Hdarwin: - symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink; - break; - } - cseek(symo); - switch(HEADTYPE) { - default: - if(iself) { - if(debug['v']) - Bprint(&bso, "%5.2f elfsym\n", cputime()); - asmelfsym(); - cflush(); - cwrite(elfstrdat, elfstrsize); - - if(debug['v']) - Bprint(&bso, "%5.2f dwarf\n", cputime()); - dwarfemitdebugsections(); - - if(linkmode == LinkExternal) - elfemitreloc(); - } - break; - case Hplan9: - asmplan9sym(); - cflush(); - - sym = linklookup(ctxt, "pclntab", 0); - if(sym != nil) { - lcsize = sym->np; - for(i=0; i < lcsize; i++) - cput(sym->p[i]); - - cflush(); - } - break; - case Hdarwin: - if(linkmode == LinkExternal) - machoemitreloc(); - break; - } - } - - ctxt->cursym = nil; - if(debug['v']) - Bprint(&bso, "%5.2f header\n", cputime()); - Bflush(&bso); - cseek(0L); - switch(HEADTYPE) { - default: - case Hplan9: /* plan 9 */ - thearch.lput(0x647); /* magic */ - thearch.lput(segtext.filelen); /* sizes */ - thearch.lput(segdata.filelen); - thearch.lput(segdata.length - segdata.filelen); - thearch.lput(symsize); /* nsyms */ - thearch.lput(entryvalue()); /* va of entry */ - thearch.lput(0L); - thearch.lput(lcsize); - break; - case Hlinux: - case Hfreebsd: - case Hnetbsd: - case Hopenbsd: - case Hnacl: - asmbelf(symo); - break; - case Hdarwin: - asmbmacho(); - break; - } - cflush(); - if(debug['c']){ - print("textsize=%ulld\n", segtext.filelen); - print("datsize=%ulld\n", segdata.filelen); - print("bsssize=%ulld\n", segdata.length - segdata.filelen); - print("symsize=%d\n", symsize); - print("lcsize=%d\n", lcsize); - print("total=%lld\n", segtext.filelen+segdata.length+symsize+lcsize); - } -} diff --git a/src/cmd/new5l/asm.go b/src/cmd/5l/asm.go similarity index 100% rename from src/cmd/new5l/asm.go rename to src/cmd/5l/asm.go diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go deleted file mode 100644 index a054a228b8..0000000000 --- a/src/cmd/5l/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -5l is the linker for the ARM. -The $GOARCH for these tools is arm. - -The flags are documented in ../ld/doc.go. - -*/ -package main diff --git a/src/cmd/new5l/l.go b/src/cmd/5l/l.go similarity index 100% rename from src/cmd/new5l/l.go rename to src/cmd/5l/l.go diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h deleted file mode 100644 index 0258d5a776..0000000000 --- a/src/cmd/5l/l.h +++ /dev/null @@ -1,66 +0,0 @@ -// Inferno utils/5l/l.h -// http://code.google.com/p/inferno-os/source/browse/utils/5l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include -#include - -enum -{ - thechar = '5', - PtrSize = 4, - IntSize = 4, - RegSize = 4, - MaxAlign = 8, // max data alignment - FuncAlign = 4, // single-instruction alignment - MINLC = 4, -}; - -#ifndef EXTERN -#define EXTERN extern -#endif - -void adddynlib(char *lib); -void adddynrel(LSym *s, Reloc *r); -void adddynrela(LSym *rel, LSym *s, Reloc *r); -void adddynsym(Link *ctxt, LSym *s); -int archreloc(Reloc *r, LSym *s, vlong *val); -vlong archrelocvariant(Reloc *r, LSym *s, vlong t); -void asmb(void); -int elfreloc1(Reloc *r, vlong sectoff); -void elfsetupplt(void); -int machoreloc1(Reloc *r, vlong sectoff); - -/* Used by ../ld/dwarf.c */ -enum -{ - DWARFREGSP = 13 -}; diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c deleted file mode 100644 index 887cc5aef4..0000000000 --- a/src/cmd/5l/obj.c +++ /dev/null @@ -1,167 +0,0 @@ -// Inferno utils/5l/obj.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Reading object files. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" -#include "../ld/macho.h" -#include "../ld/dwarf.h" -#include - -void -main(int argc, char **argv) -{ - linkarchinit(); - ldmain(argc, argv); -} - - -void -linkarchinit(void) -{ - thestring = "arm"; - thelinkarch = &linkarm; - - thearch.thechar = thechar; - thearch.ptrsize = thelinkarch->ptrsize; - thearch.intsize = thelinkarch->ptrsize; - thearch.regsize = thelinkarch->regsize; - thearch.funcalign = FuncAlign; - thearch.maxalign = MaxAlign; - thearch.minlc = MINLC; - thearch.dwarfregsp = DWARFREGSP; - - thearch.adddynlib = adddynlib; - thearch.adddynrel = adddynrel; - thearch.adddynsym = adddynsym; - thearch.archinit = archinit; - thearch.archreloc = archreloc; - thearch.archrelocvariant = archrelocvariant; - thearch.asmb = asmb; - thearch.elfreloc1 = elfreloc1; - thearch.elfsetupplt = elfsetupplt; - thearch.gentext = gentext; - thearch.machoreloc1 = machoreloc1; - thearch.lput = lputl; - thearch.wput = wputl; - thearch.vput = vputl; - - thearch.linuxdynld = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI - thearch.freebsddynld = "/usr/libexec/ld-elf.so.1"; - thearch.openbsddynld = "XXX"; - thearch.netbsddynld = "/libexec/ld.elf_so"; - thearch.dragonflydynld = "XXX"; - thearch.solarisdynld = "XXX"; -} - -void -archinit(void) -{ - LSym *s; - - // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when - // Go was built; see ../../make.bash. - if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) - linkmode = LinkInternal; - - switch(HEADTYPE) { - default: - if(linkmode == LinkAuto) - linkmode = LinkInternal; - if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0) - sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE)); - break; - case Hlinux: - case Hfreebsd: - case Hnacl: - case Hdarwin: - break; - } - - switch(HEADTYPE) { - default: - diag("unknown -H option"); - errorexit(); - case Hplan9: /* plan 9 */ - HEADR = 32L; - if(INITTEXT == -1) - INITTEXT = 4128; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - case Hlinux: /* arm elf */ - case Hfreebsd: - case Hnetbsd: - debug['d'] = 0; // with dynamic linking - elfinit(); - HEADR = ELFRESERVE; - if(INITTEXT == -1) - INITTEXT = 0x10000 + HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - case Hnacl: - elfinit(); - HEADR = 0x10000; - funcalign = 16; - if(INITTEXT == -1) - INITTEXT = 0x20000; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 0x10000; - break; - case Hdarwin: /* apple MACH */ - debug['w'] = 1; // disable DWARF generataion - machoinit(); - HEADR = INITIAL_MACHO_HEADR; - if(INITTEXT == -1) - INITTEXT = 4096+HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - } - if(INITDAT != 0 && INITRND != 0) - print("warning: -D0x%ux is ignored because of -R0x%ux\n", - INITDAT, INITRND); - - // embed goarm to runtime.goarm - s = linklookup(ctxt, "runtime.goarm", 0); - s->type = SRODATA; - adduint8(ctxt, s, ctxt->goarm); -} diff --git a/src/cmd/new5l/obj.go b/src/cmd/5l/obj.go similarity index 100% rename from src/cmd/new5l/obj.go rename to src/cmd/5l/obj.go diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile deleted file mode 100644 index 3f528d7517..0000000000 --- a/src/cmd/6l/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c deleted file mode 100644 index b817cf5ce5..0000000000 --- a/src/cmd/6l/asm.c +++ /dev/null @@ -1,795 +0,0 @@ -// Inferno utils/6l/asm.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Writing object files. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" -#include "../ld/dwarf.h" -#include "../ld/macho.h" -#include "../ld/pe.h" - -uint32 -PADDR(uint32 x) -{ - return x & ~0x80000000; -} - -char zeroes[32]; - -static int -needlib(char *name) -{ - char *p; - LSym *s; - - if(*name == '\0') - return 0; - - /* reuse hash code in symbol table */ - p = smprint(".elfload.%s", name); - s = linklookup(ctxt, p, 0); - free(p); - if(s->type == 0) { - s->type = 100; // avoid SDATA, etc. - return 1; - } - return 0; -} - -static void addpltsym(LSym*); -static void addgotsym(LSym*); - -void -gentext(void) -{ -} - -void -adddynrela(LSym *rela, LSym *s, Reloc *r) -{ - addaddrplus(ctxt, rela, s, r->off); - adduint64(ctxt, rela, R_X86_64_RELATIVE); - addaddrplus(ctxt, rela, r->sym, r->add); // Addend -} - -void -adddynrel(LSym *s, Reloc *r) -{ - LSym *targ, *rela, *got; - - targ = r->sym; - ctxt->cursym = s; - - switch(r->type) { - default: - if(r->type >= 256) { - diag("unexpected relocation type %d", r->type); - return; - } - break; - - // Handle relocations found in ELF object files. - case 256 + R_X86_64_PC32: - if(targ->type == SDYNIMPORT) - diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name); - if(targ->type == 0 || targ->type == SXREF) - diag("unknown symbol %s in pcrel", targ->name); - r->type = R_PCREL; - r->add += 4; - return; - - case 256 + R_X86_64_PLT32: - r->type = R_PCREL; - r->add += 4; - if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = linklookup(ctxt, ".plt", 0); - r->add += targ->plt; - } - return; - - case 256 + R_X86_64_GOTPCREL: - if(targ->type != SDYNIMPORT) { - // have symbol - if(r->off >= 2 && s->p[r->off-2] == 0x8b) { - // turn MOVQ of GOT entry into LEAQ of symbol itself - s->p[r->off-2] = 0x8d; - r->type = R_PCREL; - r->add += 4; - return; - } - // fall back to using GOT and hope for the best (CMOV*) - // TODO: just needs relocation, no need to put in .dynsym - } - addgotsym(targ); - r->type = R_PCREL; - r->sym = linklookup(ctxt, ".got", 0); - r->add += 4; - r->add += targ->got; - return; - - case 256 + R_X86_64_64: - if(targ->type == SDYNIMPORT) - diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name); - r->type = R_ADDR; - return; - - // Handle relocations found in Mach-O object files. - case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0: - case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0: - case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0: - // TODO: What is the difference between all these? - r->type = R_ADDR; - if(targ->type == SDYNIMPORT) - diag("unexpected reloc for dynamic symbol %s", targ->name); - return; - - case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1: - if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = linklookup(ctxt, ".plt", 0); - r->add = targ->plt; - r->type = R_PCREL; - return; - } - // fall through - case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1: - case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1: - case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1: - case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1: - case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1: - r->type = R_PCREL; - if(targ->type == SDYNIMPORT) - diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name); - return; - - case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1: - if(targ->type != SDYNIMPORT) { - // have symbol - // turn MOVQ of GOT entry into LEAQ of symbol itself - if(r->off < 2 || s->p[r->off-2] != 0x8b) { - diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name); - return; - } - s->p[r->off-2] = 0x8d; - r->type = R_PCREL; - return; - } - // fall through - case 512 + MACHO_X86_64_RELOC_GOT*2 + 1: - if(targ->type != SDYNIMPORT) - diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); - addgotsym(targ); - r->type = R_PCREL; - r->sym = linklookup(ctxt, ".got", 0); - r->add += targ->got; - return; - } - - // Handle references to ELF symbols from our own object files. - if(targ->type != SDYNIMPORT) - return; - - switch(r->type) { - case R_CALL: - case R_PCREL: - addpltsym(targ); - r->sym = linklookup(ctxt, ".plt", 0); - r->add = targ->plt; - return; - - case R_ADDR: - if(s->type == STEXT && iself) { - // The code is asking for the address of an external - // function. We provide it with the address of the - // correspondent GOT symbol. - addgotsym(targ); - r->sym = linklookup(ctxt, ".got", 0); - r->add += targ->got; - return; - } - if(s->type != SDATA) - break; - if(iself) { - adddynsym(ctxt, targ); - rela = linklookup(ctxt, ".rela", 0); - addaddrplus(ctxt, rela, s, r->off); - if(r->siz == 8) - adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_64)); - else - adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_32)); - adduint64(ctxt, rela, r->add); - r->type = 256; // ignore during relocsym - return; - } - if(HEADTYPE == Hdarwin && s->size == thearch.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. - // Instead, interpret the C declaration - // void *_Cvar_stderr = &stderr; - // as making _Cvar_stderr the name of a GOT entry - // for stderr. This is separate from the usual GOT entry, - // 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. - adddynsym(ctxt, targ); - got = linklookup(ctxt, ".got", 0); - s->type = got->type | SSUB; - s->outer = got; - s->sub = got->sub; - got->sub = s; - s->value = got->size; - adduint64(ctxt, got, 0); - adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid); - r->type = 256; // ignore during relocsym - return; - } - break; - } - - ctxt->cursym = s; - diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); -} - -int -elfreloc1(Reloc *r, vlong sectoff) -{ - int32 elfsym; - - thearch.vput(sectoff); - - elfsym = r->xsym->elfsym; - switch(r->type) { - default: - return -1; - - case R_ADDR: - if(r->siz == 4) - thearch.vput(R_X86_64_32 | (uint64)elfsym<<32); - else if(r->siz == 8) - thearch.vput(R_X86_64_64 | (uint64)elfsym<<32); - else - return -1; - break; - - case R_TLS_LE: - if(r->siz == 4) - thearch.vput(R_X86_64_TPOFF32 | (uint64)elfsym<<32); - else - return -1; - break; - - case R_CALL: - if(r->siz == 4) { - if(r->xsym->type == SDYNIMPORT) - thearch.vput(R_X86_64_GOTPCREL | (uint64)elfsym<<32); - else - thearch.vput(R_X86_64_PC32 | (uint64)elfsym<<32); - } else - return -1; - break; - - case R_PCREL: - if(r->siz == 4) { - thearch.vput(R_X86_64_PC32 | (uint64)elfsym<<32); - } else - return -1; - break; - - case R_TLS: - if(r->siz == 4) { - if(flag_shared) - thearch.vput(R_X86_64_GOTTPOFF | (uint64)elfsym<<32); - else - thearch.vput(R_X86_64_TPOFF32 | (uint64)elfsym<<32); - } else - return -1; - break; - } - - thearch.vput(r->xadd); - return 0; -} - -int -machoreloc1(Reloc *r, vlong sectoff) -{ - uint32 v; - LSym *rs; - - rs = r->xsym; - - if(rs->type == SHOSTOBJ || r->type == R_PCREL) { - if(rs->dynid < 0) { - diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type); - return -1; - } - v = rs->dynid; - v |= 1<<27; // external relocation - } else { - v = ((Section*)rs->sect)->extnum; - if(v == 0) { - diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, ((Section*)rs->sect)->name, rs->type); - return -1; - } - } - - switch(r->type) { - default: - return -1; - case R_ADDR: - v |= MACHO_X86_64_RELOC_UNSIGNED<<28; - break; - case R_CALL: - v |= 1<<24; // pc-relative bit - v |= MACHO_X86_64_RELOC_BRANCH<<28; - break; - case R_PCREL: - // NOTE: Only works with 'external' relocation. Forced above. - v |= 1<<24; // pc-relative bit - v |= MACHO_X86_64_RELOC_SIGNED<<28; - } - - switch(r->siz) { - default: - return -1; - case 1: - v |= 0<<25; - break; - case 2: - v |= 1<<25; - break; - case 4: - v |= 2<<25; - break; - case 8: - v |= 3<<25; - break; - } - - thearch.lput(sectoff); - thearch.lput(v); - return 0; -} - -int -archreloc(Reloc *r, LSym *s, vlong *val) -{ - USED(r); - USED(s); - USED(val); - return -1; -} - -vlong -archrelocvariant(Reloc *r, LSym *s, vlong t) -{ - USED(r); - USED(s); - sysfatal("unexpected relocation variant"); - return t; -} - -void -elfsetupplt(void) -{ - LSym *plt, *got; - - plt = linklookup(ctxt, ".plt", 0); - got = linklookup(ctxt, ".got.plt", 0); - if(plt->size == 0) { - // pushq got+8(IP) - adduint8(ctxt, plt, 0xff); - adduint8(ctxt, plt, 0x35); - addpcrelplus(ctxt, plt, got, 8); - - // jmpq got+16(IP) - adduint8(ctxt, plt, 0xff); - adduint8(ctxt, plt, 0x25); - addpcrelplus(ctxt, plt, got, 16); - - // nopl 0(AX) - adduint32(ctxt, plt, 0x00401f0f); - - // assume got->size == 0 too - addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0); - adduint64(ctxt, got, 0); - adduint64(ctxt, got, 0); - } -} - -static void -addpltsym(LSym *s) -{ - if(s->plt >= 0) - return; - - adddynsym(ctxt, s); - - if(iself) { - LSym *plt, *got, *rela; - - plt = linklookup(ctxt, ".plt", 0); - got = linklookup(ctxt, ".got.plt", 0); - rela = linklookup(ctxt, ".rela.plt", 0); - if(plt->size == 0) - elfsetupplt(); - - // jmpq *got+size(IP) - adduint8(ctxt, plt, 0xff); - adduint8(ctxt, plt, 0x25); - addpcrelplus(ctxt, plt, got, got->size); - - // add to got: pointer to current pos in plt - addaddrplus(ctxt, got, plt, plt->size); - - // pushq $x - adduint8(ctxt, plt, 0x68); - adduint32(ctxt, plt, (got->size-24-8)/8); - - // jmpq .plt - adduint8(ctxt, plt, 0xe9); - adduint32(ctxt, plt, -(plt->size+4)); - - // rela - addaddrplus(ctxt, rela, got, got->size-8); - adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT)); - adduint64(ctxt, rela, 0); - - s->plt = plt->size - 16; - } else if(HEADTYPE == Hdarwin) { - // 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 - // section just so. I'm too lazy (ha!) to do that - // so for now we'll just use non-lazy pointers, - // which don't need to be told which library to use. - // - // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html - // has details about what we're avoiding. - - LSym *plt; - - addgotsym(s); - plt = linklookup(ctxt, ".plt", 0); - - adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid); - - // jmpq *got+size(IP) - s->plt = plt->size; - - adduint8(ctxt, plt, 0xff); - adduint8(ctxt, plt, 0x25); - addpcrelplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got); - } else { - diag("addpltsym: unsupported binary format"); - } -} - -static void -addgotsym(LSym *s) -{ - LSym *got, *rela; - - if(s->got >= 0) - return; - - adddynsym(ctxt, s); - got = linklookup(ctxt, ".got", 0); - s->got = got->size; - adduint64(ctxt, got, 0); - - if(iself) { - rela = linklookup(ctxt, ".rela", 0); - addaddrplus(ctxt, rela, got, s->got); - adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT)); - adduint64(ctxt, rela, 0); - } else if(HEADTYPE == Hdarwin) { - adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid); - } else { - diag("addgotsym: unsupported binary format"); - } -} - -void -adddynsym(Link *ctxt, LSym *s) -{ - LSym *d; - int t; - char *name; - - if(s->dynid >= 0) - return; - - if(iself) { - s->dynid = nelfsym++; - - d = linklookup(ctxt, ".dynsym", 0); - - name = s->extname; - adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); - /* type */ - t = STB_GLOBAL << 4; - if(s->cgoexport && (s->type&SMASK) == STEXT) - t |= STT_FUNC; - else - t |= STT_OBJECT; - adduint8(ctxt, d, t); - - /* reserved */ - adduint8(ctxt, d, 0); - - /* section where symbol is defined */ - if(s->type == SDYNIMPORT) - adduint16(ctxt, d, SHN_UNDEF); - else - adduint16(ctxt, d, 1); - - /* value */ - if(s->type == SDYNIMPORT) - adduint64(ctxt, d, 0); - else - addaddr(ctxt, d, s); - - /* size of object */ - adduint64(ctxt, d, s->size); - - if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) { - elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, - addstring(linklookup(ctxt, ".dynstr", 0), s->dynimplib)); - } - } else if(HEADTYPE == Hdarwin) { - diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); - } else if(HEADTYPE == Hwindows) { - // already taken care of - } else { - diag("adddynsym: unsupported binary format"); - } -} - -void -adddynlib(char *lib) -{ - LSym *s; - - if(!needlib(lib)) - return; - - if(iself) { - s = linklookup(ctxt, ".dynstr", 0); - if(s->size == 0) - addstring(s, ""); - elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); - } else if(HEADTYPE == Hdarwin) { - machoadddynlib(lib); - } else { - diag("adddynlib: unsupported binary format"); - } -} - -void -asmb(void) -{ - int32 magic; - int i; - vlong vl, symo, dwarfoff, machlink; - Section *sect; - LSym *sym; - - if(debug['v']) - Bprint(&bso, "%5.2f asmb\n", cputime()); - Bflush(&bso); - - if(debug['v']) - Bprint(&bso, "%5.2f codeblk\n", cputime()); - Bflush(&bso); - - if(iself) - asmbelfsetup(); - - sect = segtext.sect; - cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); - codeblk(sect->vaddr, sect->length); - for(sect = sect->next; sect != nil; sect = sect->next) { - cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); - datblk(sect->vaddr, sect->length); - } - - if(segrodata.filelen > 0) { - if(debug['v']) - Bprint(&bso, "%5.2f rodatblk\n", cputime()); - Bflush(&bso); - - cseek(segrodata.fileoff); - datblk(segrodata.vaddr, segrodata.filelen); - } - - if(debug['v']) - Bprint(&bso, "%5.2f datblk\n", cputime()); - Bflush(&bso); - - cseek(segdata.fileoff); - datblk(segdata.vaddr, segdata.filelen); - - machlink = 0; - if(HEADTYPE == Hdarwin) { - if(debug['v']) - Bprint(&bso, "%5.2f dwarf\n", cputime()); - - dwarfoff = rnd(HEADR+segtext.length, INITRND) + rnd(segdata.filelen, INITRND); - cseek(dwarfoff); - - segdwarf.fileoff = cpos(); - dwarfemitdebugsections(); - segdwarf.filelen = cpos() - segdwarf.fileoff; - - machlink = domacholink(); - } - - switch(HEADTYPE) { - default: - diag("unknown header type %d", HEADTYPE); - case Hplan9: - case Helf: - break; - case Hdarwin: - debug['8'] = 1; /* 64-bit addresses */ - break; - case Hlinux: - case Hfreebsd: - case Hnetbsd: - case Hopenbsd: - case Hdragonfly: - case Hsolaris: - debug['8'] = 1; /* 64-bit addresses */ - break; - case Hnacl: - case Hwindows: - break; - } - - symsize = 0; - spsize = 0; - lcsize = 0; - symo = 0; - if(!debug['s']) { - if(debug['v']) - Bprint(&bso, "%5.2f sym\n", cputime()); - Bflush(&bso); - switch(HEADTYPE) { - default: - case Hplan9: - case Helf: - debug['s'] = 1; - symo = segdata.fileoff+segdata.filelen; - break; - case Hdarwin: - symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink; - break; - case Hlinux: - case Hfreebsd: - case Hnetbsd: - case Hopenbsd: - case Hdragonfly: - case Hsolaris: - case Hnacl: - symo = segdata.fileoff+segdata.filelen; - symo = rnd(symo, INITRND); - break; - case Hwindows: - symo = segdata.fileoff+segdata.filelen; - symo = rnd(symo, PEFILEALIGN); - break; - } - cseek(symo); - switch(HEADTYPE) { - default: - if(iself) { - cseek(symo); - asmelfsym(); - cflush(); - cwrite(elfstrdat, elfstrsize); - - if(debug['v']) - Bprint(&bso, "%5.2f dwarf\n", cputime()); - - dwarfemitdebugsections(); - - if(linkmode == LinkExternal) - elfemitreloc(); - } - break; - case Hplan9: - asmplan9sym(); - cflush(); - - sym = linklookup(ctxt, "pclntab", 0); - if(sym != nil) { - lcsize = sym->np; - for(i=0; i < lcsize; i++) - cput(sym->p[i]); - - cflush(); - } - break; - case Hwindows: - if(debug['v']) - Bprint(&bso, "%5.2f dwarf\n", cputime()); - - dwarfemitdebugsections(); - break; - case Hdarwin: - if(linkmode == LinkExternal) - machoemitreloc(); - break; - } - } - - if(debug['v']) - Bprint(&bso, "%5.2f headr\n", cputime()); - Bflush(&bso); - cseek(0L); - switch(HEADTYPE) { - default: - case Hplan9: /* plan9 */ - magic = 4*26*26+7; - magic |= 0x00008000; /* fat header */ - lputb(magic); /* magic */ - lputb(segtext.filelen); /* sizes */ - lputb(segdata.filelen); - lputb(segdata.length - segdata.filelen); - lputb(symsize); /* nsyms */ - vl = entryvalue(); - lputb(PADDR(vl)); /* va of entry */ - lputb(spsize); /* sp offsets */ - lputb(lcsize); /* line offsets */ - vputb(vl); /* va of entry */ - break; - case Hdarwin: - asmbmacho(); - break; - case Hlinux: - case Hfreebsd: - case Hnetbsd: - case Hopenbsd: - case Hdragonfly: - case Hsolaris: - case Hnacl: - asmbelf(symo); - break; - case Hwindows: - asmbpe(); - break; - } - cflush(); -} diff --git a/src/cmd/new6l/asm.go b/src/cmd/6l/asm.go similarity index 100% rename from src/cmd/new6l/asm.go rename to src/cmd/6l/asm.go diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go deleted file mode 100644 index 6287dd9bec..0000000000 --- a/src/cmd/6l/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -6l is the linker for the x86-64. -The $GOARCH for these tools is amd64. - -The flags are documented in ../ld/doc.go. - -*/ -package main diff --git a/src/cmd/new6l/l.go b/src/cmd/6l/l.go similarity index 100% rename from src/cmd/new6l/l.go rename to src/cmd/6l/l.go diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h deleted file mode 100644 index b314e25836..0000000000 --- a/src/cmd/6l/l.h +++ /dev/null @@ -1,67 +0,0 @@ -// Inferno utils/6l/l.h -// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include -#include - -#ifndef EXTERN -#define EXTERN extern -#endif - -enum -{ - thechar = '6', - MaxAlign = 32, // max data alignment - FuncAlign = 16 -}; - -enum -{ - MINLC = 1, -}; - -void adddynlib(char *lib); -void adddynrel(LSym *s, Reloc *r); -void adddynrela(LSym *rela, LSym *s, Reloc *r); -void adddynsym(Link *ctxt, LSym *s); -int archreloc(Reloc *r, LSym *s, vlong *val); -vlong archrelocvariant(Reloc *r, LSym *s, vlong t); -void asmb(void); -int elfreloc1(Reloc *r, vlong sectoff); -void elfsetupplt(void); -int machoreloc1(Reloc *r, vlong sectoff); - -/* Used by ../ld/dwarf.c */ -enum -{ - DWARFREGSP = 7 -}; diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c deleted file mode 100644 index ebd4bae894..0000000000 --- a/src/cmd/6l/obj.c +++ /dev/null @@ -1,191 +0,0 @@ -// Inferno utils/6l/obj.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Reading object files. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" -#include "../ld/macho.h" -#include "../ld/dwarf.h" -#include "../ld/pe.h" -#include - -void -main(int argc, char **argv) -{ - linkarchinit(); - ldmain(argc, argv); -} - -void -linkarchinit(void) -{ - thestring = "amd64"; - thelinkarch = &linkamd64; - if(strcmp(getgoarch(), "amd64p32") == 0) - thelinkarch = &linkamd64p32; - - thearch.thechar = thechar; - thearch.ptrsize = thelinkarch->ptrsize; - thearch.intsize = thelinkarch->ptrsize; - thearch.regsize = thelinkarch->regsize; - thearch.funcalign = FuncAlign; - thearch.maxalign = MaxAlign; - thearch.minlc = MINLC; - thearch.dwarfregsp = DWARFREGSP; - - thearch.adddynlib = adddynlib; - thearch.adddynrel = adddynrel; - thearch.adddynsym = adddynsym; - thearch.archinit = archinit; - thearch.archreloc = archreloc; - thearch.archrelocvariant = archrelocvariant; - thearch.asmb = asmb; - thearch.elfreloc1 = elfreloc1; - thearch.elfsetupplt = elfsetupplt; - thearch.gentext = gentext; - thearch.machoreloc1 = machoreloc1; - thearch.lput = lputl; - thearch.wput = wputl; - thearch.vput = vputl; - - thearch.linuxdynld = "/lib64/ld-linux-x86-64.so.2"; - thearch.freebsddynld = "/libexec/ld-elf.so.1"; - thearch.openbsddynld = "/usr/libexec/ld.so"; - thearch.netbsddynld = "/libexec/ld.elf_so"; - thearch.dragonflydynld = "/usr/libexec/ld-elf.so.2"; - thearch.solarisdynld = "/lib/amd64/ld.so.1"; -} - -void -archinit(void) -{ - // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when - // Go was built; see ../../make.bash. - if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) - linkmode = LinkInternal; - - if(flag_shared) - linkmode = LinkExternal; - - switch(HEADTYPE) { - default: - if(linkmode == LinkAuto) - linkmode = LinkInternal; - if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0) - sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE)); - break; - case Hdarwin: - case Hdragonfly: - case Hfreebsd: - case Hlinux: - case Hnacl: - case Hnetbsd: - case Hopenbsd: - case Hsolaris: - break; - } - - switch(HEADTYPE) { - default: - diag("unknown -H option"); - errorexit(); - case Hplan9: /* plan 9 */ - HEADR = 32L + 8L; - if(INITTEXT == -1) - INITTEXT = 0x200000+HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 0x200000; - break; - case Helf: /* elf32 executable */ - HEADR = rnd(52L+3*32L, 16); - if(INITTEXT == -1) - INITTEXT = 0x80110000L; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - case Hdarwin: /* apple MACH */ - machoinit(); - HEADR = INITIAL_MACHO_HEADR; - if(INITRND == -1) - INITRND = 4096; - if(INITTEXT == -1) - INITTEXT = 4096+HEADR; - if(INITDAT == -1) - INITDAT = 0; - break; - case Hlinux: /* elf64 executable */ - case Hfreebsd: /* freebsd */ - case Hnetbsd: /* netbsd */ - case Hopenbsd: /* openbsd */ - case Hdragonfly: /* dragonfly */ - case Hsolaris: /* solaris */ - elfinit(); - HEADR = ELFRESERVE; - if(INITTEXT == -1) - INITTEXT = (1<<22)+HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - case Hnacl: - elfinit(); - debug['w']++; // disable dwarf, which gets confused and is useless anyway - HEADR = 0x10000; - funcalign = 32; - if(INITTEXT == -1) - INITTEXT = 0x20000; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 0x10000; - break; - case Hwindows: /* PE executable */ - peinit(); - HEADR = PEFILEHEADR; - if(INITTEXT == -1) - INITTEXT = PEBASE+PESECTHEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = PESECTALIGN; - break; - } - - if(INITDAT != 0 && INITRND != 0) - print("warning: -D0x%llux is ignored because of -R0x%ux\n", - INITDAT, INITRND); -} diff --git a/src/cmd/new6l/obj.go b/src/cmd/6l/obj.go similarity index 100% rename from src/cmd/new6l/obj.go rename to src/cmd/6l/obj.go diff --git a/src/cmd/new6l/z.go b/src/cmd/6l/z.go similarity index 100% rename from src/cmd/new6l/z.go rename to src/cmd/6l/z.go diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile deleted file mode 100644 index 3f528d7517..0000000000 --- a/src/cmd/8l/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c deleted file mode 100644 index d7622f7f97..0000000000 --- a/src/cmd/8l/asm.c +++ /dev/null @@ -1,707 +0,0 @@ -// Inferno utils/8l/asm.c -// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Writing object files. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" -#include "../ld/dwarf.h" -#include "../ld/macho.h" -#include "../ld/pe.h" - -static int -needlib(char *name) -{ - char *p; - LSym *s; - - if(*name == '\0') - return 0; - - /* reuse hash code in symbol table */ - p = smprint(".dynlib.%s", name); - s = linklookup(ctxt, p, 0); - free(p); - if(s->type == 0) { - s->type = 100; // avoid SDATA, etc. - return 1; - } - return 0; -} - -static void addpltsym(Link*, LSym*); -static void addgotsym(Link*, LSym*); - -void -gentext(void) -{ -} - -void -adddynrela(LSym *rela, LSym *s, Reloc *r) -{ - USED(rela); - USED(s); - USED(r); - sysfatal("adddynrela not implemented"); -} - -void -adddynrel(LSym *s, Reloc *r) -{ - LSym *targ, *rel, *got; - - targ = r->sym; - ctxt->cursym = s; - - switch(r->type) { - default: - if(r->type >= 256) { - diag("unexpected relocation type %d", r->type); - return; - } - break; - - // Handle relocations found in ELF object files. - case 256 + R_386_PC32: - if(targ->type == SDYNIMPORT) - diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name); - if(targ->type == 0 || targ->type == SXREF) - diag("unknown symbol %s in pcrel", targ->name); - r->type = R_PCREL; - r->add += 4; - return; - - case 256 + R_386_PLT32: - r->type = R_PCREL; - r->add += 4; - if(targ->type == SDYNIMPORT) { - addpltsym(ctxt, targ); - r->sym = linklookup(ctxt, ".plt", 0); - r->add += targ->plt; - } - return; - - case 256 + R_386_GOT32: - if(targ->type != SDYNIMPORT) { - // have symbol - if(r->off >= 2 && s->p[r->off-2] == 0x8b) { - // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT. - s->p[r->off-2] = 0x8d; - r->type = R_GOTOFF; - return; - } - if(r->off >= 2 && s->p[r->off-2] == 0xff && s->p[r->off-1] == 0xb3) { - // turn PUSHL of GOT entry into PUSHL of symbol itself. - // use unnecessary SS prefix to keep instruction same length. - s->p[r->off-2] = 0x36; - s->p[r->off-1] = 0x68; - r->type = R_ADDR; - return; - } - diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); - return; - } - addgotsym(ctxt, targ); - r->type = R_CONST; // write r->add during relocsym - r->sym = nil; - r->add += targ->got; - return; - - case 256 + R_386_GOTOFF: - r->type = R_GOTOFF; - return; - - case 256 + R_386_GOTPC: - r->type = R_PCREL; - r->sym = linklookup(ctxt, ".got", 0); - r->add += 4; - return; - - case 256 + R_386_32: - if(targ->type == SDYNIMPORT) - diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name); - r->type = R_ADDR; - return; - - case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0: - r->type = R_ADDR; - if(targ->type == SDYNIMPORT) - diag("unexpected reloc for dynamic symbol %s", targ->name); - return; - - case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1: - if(targ->type == SDYNIMPORT) { - addpltsym(ctxt, targ); - r->sym = linklookup(ctxt, ".plt", 0); - r->add = targ->plt; - r->type = R_PCREL; - return; - } - r->type = R_PCREL; - return; - - case 512 + MACHO_FAKE_GOTPCREL: - if(targ->type != SDYNIMPORT) { - // have symbol - // turn MOVL of GOT entry into LEAL of symbol itself - if(r->off < 2 || s->p[r->off-2] != 0x8b) { - diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); - return; - } - s->p[r->off-2] = 0x8d; - r->type = R_PCREL; - return; - } - addgotsym(ctxt, targ); - r->sym = linklookup(ctxt, ".got", 0); - r->add += targ->got; - r->type = R_PCREL; - return; - } - - // Handle references to ELF symbols from our own object files. - if(targ->type != SDYNIMPORT) - return; - - switch(r->type) { - case R_CALL: - case R_PCREL: - addpltsym(ctxt, targ); - r->sym = linklookup(ctxt, ".plt", 0); - r->add = targ->plt; - return; - - case R_ADDR: - if(s->type != SDATA) - break; - if(iself) { - adddynsym(ctxt, targ); - rel = linklookup(ctxt, ".rel", 0); - addaddrplus(ctxt, rel, s, r->off); - adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_386_32)); - r->type = R_CONST; // write r->add during relocsym - r->sym = nil; - return; - } - if(HEADTYPE == Hdarwin && s->size == 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. - // Instead, interpret the C declaration - // void *_Cvar_stderr = &stderr; - // as making _Cvar_stderr the name of a GOT entry - // for stderr. This is separate from the usual GOT entry, - // 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. - adddynsym(ctxt, targ); - got = linklookup(ctxt, ".got", 0); - s->type = got->type | SSUB; - s->outer = got; - s->sub = got->sub; - got->sub = s; - s->value = got->size; - adduint32(ctxt, got, 0); - adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid); - r->type = 256; // ignore during relocsym - return; - } - break; - } - - ctxt->cursym = s; - diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); -} - -int -elfreloc1(Reloc *r, vlong sectoff) -{ - int32 elfsym; - - thearch.lput(sectoff); - - elfsym = r->xsym->elfsym; - switch(r->type) { - default: - return -1; - - case R_ADDR: - if(r->siz == 4) - thearch.lput(R_386_32 | elfsym<<8); - else - return -1; - break; - - case R_CALL: - case R_PCREL: - if(r->siz == 4) - thearch.lput(R_386_PC32 | elfsym<<8); - else - return -1; - break; - - case R_TLS_LE: - case R_TLS_IE: - if(r->siz == 4) - thearch.lput(R_386_TLS_LE | elfsym<<8); - else - return -1; - } - - return 0; -} - -int -machoreloc1(Reloc *r, vlong sectoff) -{ - uint32 v; - LSym *rs; - - rs = r->xsym; - - if(rs->type == SHOSTOBJ) { - if(rs->dynid < 0) { - diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type); - return -1; - } - v = rs->dynid; - v |= 1<<27; // external relocation - } else { - v = ((Section*)rs->sect)->extnum; - if(v == 0) { - diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, ((Section*)rs->sect)->name, rs->type); - return -1; - } - } - - switch(r->type) { - default: - return -1; - case R_ADDR: - v |= MACHO_GENERIC_RELOC_VANILLA<<28; - break; - case R_CALL: - case R_PCREL: - v |= 1<<24; // pc-relative bit - v |= MACHO_GENERIC_RELOC_VANILLA<<28; - break; - } - - switch(r->siz) { - default: - return -1; - case 1: - v |= 0<<25; - break; - case 2: - v |= 1<<25; - break; - case 4: - v |= 2<<25; - break; - case 8: - v |= 3<<25; - break; - } - - thearch.lput(sectoff); - thearch.lput(v); - return 0; -} - -int -archreloc(Reloc *r, LSym *s, vlong *val) -{ - USED(s); - if(linkmode == LinkExternal) - return -1; - switch(r->type) { - case R_CONST: - *val = r->add; - return 0; - case R_GOTOFF: - *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); - return 0; - } - return -1; -} - -vlong -archrelocvariant(Reloc *r, LSym *s, vlong t) -{ - USED(r); - USED(s); - sysfatal("unexpected relocation variant"); - return t; -} - -void -elfsetupplt(void) -{ - LSym *plt, *got; - - plt = linklookup(ctxt, ".plt", 0); - got = linklookup(ctxt, ".got.plt", 0); - if(plt->size == 0) { - // pushl got+4 - adduint8(ctxt, plt, 0xff); - adduint8(ctxt, plt, 0x35); - addaddrplus(ctxt, plt, got, 4); - - // jmp *got+8 - adduint8(ctxt, plt, 0xff); - adduint8(ctxt, plt, 0x25); - addaddrplus(ctxt, plt, got, 8); - - // zero pad - adduint32(ctxt, plt, 0); - - // assume got->size == 0 too - addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0); - adduint32(ctxt, got, 0); - adduint32(ctxt, got, 0); - } -} - -static void -addpltsym(Link *ctxt, LSym *s) -{ - LSym *plt, *got, *rel; - - if(s->plt >= 0) - return; - - adddynsym(ctxt, s); - - if(iself) { - plt = linklookup(ctxt, ".plt", 0); - got = linklookup(ctxt, ".got.plt", 0); - rel = linklookup(ctxt, ".rel.plt", 0); - if(plt->size == 0) - elfsetupplt(); - - // jmpq *got+size - adduint8(ctxt, plt, 0xff); - adduint8(ctxt, plt, 0x25); - addaddrplus(ctxt, plt, got, got->size); - - // add to got: pointer to current pos in plt - addaddrplus(ctxt, got, plt, plt->size); - - // pushl $x - adduint8(ctxt, plt, 0x68); - adduint32(ctxt, plt, rel->size); - - // jmp .plt - adduint8(ctxt, plt, 0xe9); - adduint32(ctxt, plt, -(plt->size+4)); - - // rel - addaddrplus(ctxt, rel, got, got->size-4); - adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT)); - - s->plt = plt->size - 16; - } else if(HEADTYPE == Hdarwin) { - // Same laziness as in 6l. - - LSym *plt; - - plt = linklookup(ctxt, ".plt", 0); - - addgotsym(ctxt, s); - - adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid); - - // jmpq *got+size(IP) - s->plt = plt->size; - - adduint8(ctxt, plt, 0xff); - adduint8(ctxt, plt, 0x25); - addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got); - } else { - diag("addpltsym: unsupported binary format"); - } -} - -static void -addgotsym(Link *ctxt, LSym *s) -{ - LSym *got, *rel; - - if(s->got >= 0) - return; - - adddynsym(ctxt, s); - got = linklookup(ctxt, ".got", 0); - s->got = got->size; - adduint32(ctxt, got, 0); - - if(iself) { - rel = linklookup(ctxt, ".rel", 0); - addaddrplus(ctxt, rel, got, s->got); - adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT)); - } else if(HEADTYPE == Hdarwin) { - adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid); - } else { - diag("addgotsym: unsupported binary format"); - } -} - -void -adddynsym(Link *ctxt, LSym *s) -{ - LSym *d; - int t; - char *name; - - if(s->dynid >= 0) - return; - - if(iself) { - s->dynid = nelfsym++; - - d = linklookup(ctxt, ".dynsym", 0); - - /* name */ - name = s->extname; - adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); - - /* value */ - if(s->type == SDYNIMPORT) - adduint32(ctxt, d, 0); - else - addaddr(ctxt, d, s); - - /* size */ - adduint32(ctxt, d, 0); - - /* type */ - t = STB_GLOBAL << 4; - if(s->cgoexport && (s->type&SMASK) == STEXT) - t |= STT_FUNC; - else - t |= STT_OBJECT; - adduint8(ctxt, d, t); - adduint8(ctxt, d, 0); - - /* shndx */ - if(s->type == SDYNIMPORT) - adduint16(ctxt, d, SHN_UNDEF); - else - adduint16(ctxt, d, 1); - } else if(HEADTYPE == Hdarwin) { - diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); - } else if(HEADTYPE == Hwindows) { - // already taken care of - } else { - diag("adddynsym: unsupported binary format"); - } -} - -void -adddynlib(char *lib) -{ - LSym *s; - - if(!needlib(lib)) - return; - - if(iself) { - s = linklookup(ctxt, ".dynstr", 0); - if(s->size == 0) - addstring(s, ""); - elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); - } else if(HEADTYPE == Hdarwin) { - machoadddynlib(lib); - } else if(HEADTYPE != Hwindows) { - diag("adddynlib: unsupported binary format"); - } -} - -void -asmb(void) -{ - int32 magic; - uint32 symo, dwarfoff, machlink; - Section *sect; - LSym *sym; - int i; - - if(debug['v']) - Bprint(&bso, "%5.2f asmb\n", cputime()); - Bflush(&bso); - - if(iself) - asmbelfsetup(); - - sect = segtext.sect; - cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); - codeblk(sect->vaddr, sect->length); - for(sect = sect->next; sect != nil; sect = sect->next) { - cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); - datblk(sect->vaddr, sect->length); - } - - if(segrodata.filelen > 0) { - if(debug['v']) - Bprint(&bso, "%5.2f rodatblk\n", cputime()); - Bflush(&bso); - - cseek(segrodata.fileoff); - datblk(segrodata.vaddr, segrodata.filelen); - } - - if(debug['v']) - Bprint(&bso, "%5.2f datblk\n", cputime()); - Bflush(&bso); - - cseek(segdata.fileoff); - datblk(segdata.vaddr, segdata.filelen); - - machlink = 0; - if(HEADTYPE == Hdarwin) { - if(debug['v']) - Bprint(&bso, "%5.2f dwarf\n", cputime()); - - dwarfoff = rnd(HEADR+segtext.length, INITRND) + rnd(segdata.filelen, INITRND); - cseek(dwarfoff); - - segdwarf.fileoff = cpos(); - dwarfemitdebugsections(); - segdwarf.filelen = cpos() - segdwarf.fileoff; - - machlink = domacholink(); - } - - symsize = 0; - spsize = 0; - lcsize = 0; - symo = 0; - if(!debug['s']) { - // TODO: rationalize - if(debug['v']) - Bprint(&bso, "%5.2f sym\n", cputime()); - Bflush(&bso); - switch(HEADTYPE) { - default: - if(iself) { - symo = segdata.fileoff+segdata.filelen; - symo = rnd(symo, INITRND); - } - break; - case Hplan9: - symo = segdata.fileoff+segdata.filelen; - break; - case Hdarwin: - symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink; - break; - case Hwindows: - symo = segdata.fileoff+segdata.filelen; - symo = rnd(symo, PEFILEALIGN); - break; - } - cseek(symo); - switch(HEADTYPE) { - default: - if(iself) { - if(debug['v']) - Bprint(&bso, "%5.2f elfsym\n", cputime()); - asmelfsym(); - cflush(); - cwrite(elfstrdat, elfstrsize); - - if(debug['v']) - Bprint(&bso, "%5.2f dwarf\n", cputime()); - dwarfemitdebugsections(); - - if(linkmode == LinkExternal) - elfemitreloc(); - } - break; - case Hplan9: - asmplan9sym(); - cflush(); - - sym = linklookup(ctxt, "pclntab", 0); - if(sym != nil) { - lcsize = sym->np; - for(i=0; i < lcsize; i++) - cput(sym->p[i]); - - cflush(); - } - break; - case Hwindows: - if(debug['v']) - Bprint(&bso, "%5.2f dwarf\n", cputime()); - dwarfemitdebugsections(); - break; - case Hdarwin: - if(linkmode == LinkExternal) - machoemitreloc(); - break; - } - } - if(debug['v']) - Bprint(&bso, "%5.2f headr\n", cputime()); - Bflush(&bso); - cseek(0L); - switch(HEADTYPE) { - default: - case Hplan9: /* plan9 */ - magic = 4*11*11+7; - lputb(magic); /* magic */ - lputb(segtext.filelen); /* sizes */ - lputb(segdata.filelen); - lputb(segdata.length - segdata.filelen); - lputb(symsize); /* nsyms */ - lputb(entryvalue()); /* va of entry */ - lputb(spsize); /* sp offsets */ - lputb(lcsize); /* line offsets */ - break; - case Hdarwin: - asmbmacho(); - break; - case Hlinux: - case Hfreebsd: - case Hnetbsd: - case Hopenbsd: - case Hdragonfly: - case Hnacl: - asmbelf(symo); - break; - case Hwindows: - asmbpe(); - break; - } - cflush(); -} diff --git a/src/cmd/new8l/asm.go b/src/cmd/8l/asm.go similarity index 100% rename from src/cmd/new8l/asm.go rename to src/cmd/8l/asm.go diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go deleted file mode 100644 index ff06bc3761..0000000000 --- a/src/cmd/8l/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -8l is the linker for the 32-bit x86. -The $GOARCH for these tools is 386. - -The flags are documented in ../ld/doc.go. - -*/ -package main diff --git a/src/cmd/new8l/l.go b/src/cmd/8l/l.go similarity index 100% rename from src/cmd/new8l/l.go rename to src/cmd/8l/l.go diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h deleted file mode 100644 index 77c06b3656..0000000000 --- a/src/cmd/8l/l.h +++ /dev/null @@ -1,66 +0,0 @@ -// Inferno utils/8l/l.h -// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include -#include - -#ifndef EXTERN -#define EXTERN extern -#endif - -enum -{ - thechar = '8', - PtrSize = 4, - IntSize = 4, - RegSize = 4, - MaxAlign = 32, // max data alignment - FuncAlign = 16, - MINLC = 1, -}; - -void adddynlib(char *lib); -void adddynrel(LSym *s, Reloc *r); -void adddynrela(LSym *rela, LSym *s, Reloc *r); -void adddynsym(Link *ctxt, LSym *s); -int archreloc(Reloc *r, LSym *s, vlong *val); -vlong archrelocvariant(Reloc *r, LSym *s, vlong t); -void asmb(void); -int elfreloc1(Reloc *r, vlong sectoff); -void elfsetupplt(void); -int machoreloc1(Reloc *r, vlong sectoff); - -/* Used by ../ld/dwarf.c */ -enum -{ - DWARFREGSP = 4 -}; diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c deleted file mode 100644 index 767db331da..0000000000 --- a/src/cmd/8l/obj.c +++ /dev/null @@ -1,175 +0,0 @@ -// Inferno utils/8l/obj.c -// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Reading object files. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" -#include "../ld/macho.h" -#include "../ld/dwarf.h" -#include "../ld/pe.h" -#include - -void -main(int argc, char **argv) -{ - linkarchinit(); - ldmain(argc, argv); -} - -void -linkarchinit(void) -{ - thestring = "386"; - thelinkarch = &link386; - - thearch.thechar = thechar; - thearch.ptrsize = thelinkarch->ptrsize; - thearch.intsize = thelinkarch->ptrsize; - thearch.regsize = thelinkarch->regsize; - thearch.funcalign = FuncAlign; - thearch.maxalign = MaxAlign; - thearch.minlc = MINLC; - thearch.dwarfregsp = DWARFREGSP; - - thearch.adddynlib = adddynlib; - thearch.adddynrel = adddynrel; - thearch.adddynsym = adddynsym; - thearch.archinit = archinit; - thearch.archreloc = archreloc; - thearch.archrelocvariant = archrelocvariant; - thearch.asmb = asmb; - thearch.elfreloc1 = elfreloc1; - thearch.elfsetupplt = elfsetupplt; - thearch.gentext = gentext; - thearch.machoreloc1 = machoreloc1; - thearch.lput = lputl; - thearch.wput = wputl; - thearch.vput = vputl; - - thearch.linuxdynld = "/lib/ld-linux.so.2"; - thearch.freebsddynld = "/usr/libexec/ld-elf.so.1"; - thearch.openbsddynld = "/usr/libexec/ld.so"; - thearch.netbsddynld = "/usr/libexec/ld.elf_so"; - thearch.dragonflydynld = "/usr/libexec/ld-elf.so.2"; - thearch.solarisdynld = "/lib/ld.so.1"; -} - -void -archinit(void) -{ - // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when - // Go was built; see ../../make.bash. - if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) - linkmode = LinkInternal; - - switch(HEADTYPE) { - default: - if(linkmode == LinkAuto) - linkmode = LinkInternal; - if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0) - sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE)); - break; - case Hdarwin: - case Hdragonfly: - case Hfreebsd: - case Hlinux: - case Hnetbsd: - case Hopenbsd: - break; - } - - switch(HEADTYPE) { - default: - diag("unknown -H option"); - errorexit(); - - case Hplan9: /* plan 9 */ - HEADR = 32L; - if(INITTEXT == -1) - INITTEXT = 4096+32; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - case Hdarwin: /* apple MACH */ - machoinit(); - HEADR = INITIAL_MACHO_HEADR; - if(INITTEXT == -1) - INITTEXT = 4096+HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - case Hlinux: /* elf32 executable */ - case Hfreebsd: - case Hnetbsd: - case Hopenbsd: - case Hdragonfly: - elfinit(); - HEADR = ELFRESERVE; - if(INITTEXT == -1) - INITTEXT = 0x08048000+HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - - case Hnacl: - elfinit(); - HEADR = 0x10000; - funcalign = 32; - if(INITTEXT == -1) - INITTEXT = 0x20000; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 0x10000; - break; - - case Hwindows: /* PE executable */ - peinit(); - HEADR = PEFILEHEADR; - if(INITTEXT == -1) - INITTEXT = PEBASE+PESECTHEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = PESECTALIGN; - break; - } - if(INITDAT != 0 && INITRND != 0) - print("warning: -D0x%llux is ignored because of -R0x%ux\n", - INITDAT, INITRND); -} diff --git a/src/cmd/new8l/obj.go b/src/cmd/8l/obj.go similarity index 100% rename from src/cmd/new8l/obj.go rename to src/cmd/8l/obj.go diff --git a/src/cmd/9l/Makefile b/src/cmd/9l/Makefile deleted file mode 100644 index 3f528d7517..0000000000 --- a/src/cmd/9l/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist diff --git a/src/cmd/9l/asm.c b/src/cmd/9l/asm.c deleted file mode 100644 index 3dbadf77b6..0000000000 --- a/src/cmd/9l/asm.c +++ /dev/null @@ -1,814 +0,0 @@ -// Inferno utils/5l/asm.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Writing object files. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" -#include "../ld/dwarf.h" - -static int -needlib(char *name) -{ - char *p; - LSym *s; - - if(*name == '\0') - return 0; - - /* reuse hash code in symbol table */ - p = smprint(".dynlib.%s", name); - s = linklookup(ctxt, p, 0); - free(p); - if(s->type == 0) { - s->type = 100; // avoid SDATA, etc. - return 1; - } - return 0; -} - -static void gencallstub(int abicase, LSym *stub, LSym *targ); -static void addpltsym(Link*, LSym*); -static LSym* ensureglinkresolver(void); - -void -gentext(void) -{ - LSym *s, *stub, **pprevtextp; - Reloc *r; - char *n; - uint32 o1; - uchar *cast; - int i; - - // The ppc64 ABI PLT has similar concepts to other - // architectures, but is laid out quite differently. When we - // see an R_PPC64_REL24 relocation to a dynamic symbol - // (indicating that the call needs to go through the PLT), we - // generate up to three stubs and reserve a PLT slot. - // - // 1) The call site will be bl x; nop (where the relocation - // applies to the bl). We rewrite this to bl x_stub; ld - // r2,24(r1). The ld is necessary because x_stub will save - // r2 (the TOC pointer) at 24(r1) (the "TOC save slot"). - // - // 2) We reserve space for a pointer in the .plt section (once - // per referenced dynamic function). .plt is a data - // section filled solely by the dynamic linker (more like - // .plt.got on other architectures). Initially, the - // dynamic linker will fill each slot with a pointer to the - // corresponding x@plt entry point. - // - // 3) We generate the "call stub" x_stub (once per dynamic - // function/object file pair). This saves the TOC in the - // TOC save slot, reads the function pointer from x's .plt - // slot and calls it like any other global entry point - // (including setting r12 to the function address). - // - // 4) We generate the "symbol resolver stub" x@plt (once per - // dynamic function). This is solely a branch to the glink - // resolver stub. - // - // 5) We generate the glink resolver stub (only once). This - // computes which symbol resolver stub we came through and - // invokes the dynamic resolver via a pointer provided by - // the dynamic linker. This will patch up the .plt slot to - // point directly at the function so future calls go - // straight from the call stub to the real function, and - // then call the function. - - // NOTE: It's possible we could make ppc64 closer to other - // architectures: ppc64's .plt is like .plt.got on other - // platforms and ppc64's .glink is like .plt on other - // platforms. - - // Find all R_PPC64_REL24 relocations that reference dynamic - // imports. Reserve PLT entries for these symbols and - // generate call stubs. The call stubs need to live in .text, - // which is why we need to do this pass this early. - // - // This assumes "case 1" from the ABI, where the caller needs - // us to save and restore the TOC pointer. - pprevtextp = &ctxt->textp; - for(s=*pprevtextp; s!=nil; pprevtextp=&s->next, s=*pprevtextp) { - for(r=s->r; rr+s->nr; r++) { - if(!(r->type == 256 + R_PPC64_REL24 && - r->sym->type == SDYNIMPORT)) - continue; - - // Reserve PLT entry and generate symbol - // resolver - addpltsym(ctxt, r->sym); - - // Generate call stub - n = smprint("%s.%s", s->name, r->sym->name); - stub = linklookup(ctxt, n, 0); - free(n); - stub->reachable |= s->reachable; - if(stub->size == 0) { - // Need outer to resolve .TOC. - stub->outer = s; - - // Link in to textp before s (we could - // do it after, but would have to skip - // the subsymbols) - *pprevtextp = stub; - stub->next = s; - pprevtextp = &stub->next; - - gencallstub(1, stub, r->sym); - } - - // Update the relocation to use the call stub - r->sym = stub; - - // Restore TOC after bl. The compiler put a - // nop here for us to overwrite. - o1 = 0xe8410018; // ld r2,24(r1) - cast = (uchar*)&o1; - for(i=0; i<4; i++) - s->p[r->off+4+i] = cast[inuxi4[i]]; - } - } -} - -// Construct a call stub in stub that calls symbol targ via its PLT -// entry. -static void -gencallstub(int abicase, LSym *stub, LSym *targ) -{ - LSym *plt; - Reloc *r; - - if(abicase != 1) - // If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC - // relocations, we'll need to implement cases 2 and 3. - sysfatal("gencallstub only implements case 1 calls"); - - plt = linklookup(ctxt, ".plt", 0); - - stub->type = STEXT; - - // Save TOC pointer in TOC save slot - adduint32(ctxt, stub, 0xf8410018); // std r2,24(r1) - - // Load the function pointer from the PLT. - r = addrel(stub); - r->off = stub->size; - r->sym = plt; - r->add = targ->plt; - r->siz = 2; - if(ctxt->arch->endian == BigEndian) - r->off += r->siz; - r->type = R_POWER_TOC; - r->variant = RV_POWER_HA; - adduint32(ctxt, stub, 0x3d820000); // addis r12,r2,targ@plt@toc@ha - r = addrel(stub); - r->off = stub->size; - r->sym = plt; - r->add = targ->plt; - r->siz = 2; - if(ctxt->arch->endian == BigEndian) - r->off += r->siz; - r->type = R_POWER_TOC; - r->variant = RV_POWER_LO; - adduint32(ctxt, stub, 0xe98c0000); // ld r12,targ@plt@toc@l(r12) - - // Jump to the loaded pointer - adduint32(ctxt, stub, 0x7d8903a6); // mtctr r12 - adduint32(ctxt, stub, 0x4e800420); // bctr -} - -void -adddynrela(LSym *rel, LSym *s, Reloc *r) -{ - USED(rel); USED(s); USED(r); - sysfatal("adddynrela not implemented"); -} - -void -adddynrel(LSym *s, Reloc *r) -{ - LSym *targ, *rela; - - targ = r->sym; - ctxt->cursym = s; - - switch(r->type) { - default: - if(r->type >= 256) { - diag("unexpected relocation type %d", r->type); - return; - } - break; - - // Handle relocations found in ELF object files. - case 256 + R_PPC64_REL24: - r->type = R_CALLPOWER; - // This is a local call, so the caller isn't setting - // up r12 and r2 is the same for the caller and - // callee. Hence, we need to go to the local entry - // point. (If we don't do this, the callee will try - // to use r12 to compute r2.) - r->add += r->sym->localentry * 4; - if(targ->type == SDYNIMPORT) - // Should have been handled in elfsetupplt - diag("unexpected R_PPC64_REL24 for dyn import"); - return; - - case 256 + R_PPC64_ADDR64: - r->type = R_ADDR; - if(targ->type == SDYNIMPORT) { - // These happen in .toc sections - adddynsym(ctxt, targ); - - rela = linklookup(ctxt, ".rela", 0); - addaddrplus(ctxt, rela, s, r->off); - adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_PPC64_ADDR64)); - adduint64(ctxt, rela, r->add); - r->type = 256; // ignore during relocsym - } - return; - - case 256 + R_PPC64_TOC16: - r->type = R_POWER_TOC; - r->variant = RV_POWER_LO | RV_CHECK_OVERFLOW; - return; - - case 256 + R_PPC64_TOC16_LO: - r->type = R_POWER_TOC; - r->variant = RV_POWER_LO; - return; - - case 256 + R_PPC64_TOC16_HA: - r->type = R_POWER_TOC; - r->variant = RV_POWER_HA | RV_CHECK_OVERFLOW; - return; - - case 256 + R_PPC64_TOC16_HI: - r->type = R_POWER_TOC; - r->variant = RV_POWER_HI | RV_CHECK_OVERFLOW; - return; - - case 256 + R_PPC64_TOC16_DS: - r->type = R_POWER_TOC; - r->variant = RV_POWER_DS | RV_CHECK_OVERFLOW; - return; - - case 256 + R_PPC64_TOC16_LO_DS: - r->type = R_POWER_TOC; - r->variant = RV_POWER_DS; - return; - - case 256 + R_PPC64_REL16_LO: - r->type = R_PCREL; - r->variant = RV_POWER_LO; - r->add += 2; // Compensate for relocation size of 2 - return; - - case 256 + R_PPC64_REL16_HI: - r->type = R_PCREL; - r->variant = RV_POWER_HI | RV_CHECK_OVERFLOW; - r->add += 2; - return; - - case 256 + R_PPC64_REL16_HA: - r->type = R_PCREL; - r->variant = RV_POWER_HA | RV_CHECK_OVERFLOW; - r->add += 2; - return; - } - - // Handle references to ELF symbols from our own object files. - if(targ->type != SDYNIMPORT) - return; - - // TODO(austin): Translate our relocations to ELF - - diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); -} - -int -elfreloc1(Reloc *r, vlong sectoff) -{ - USED(r); USED(sectoff); - // TODO(minux) - return -1; -} - -void -elfsetupplt(void) -{ - LSym *plt; - - plt = linklookup(ctxt, ".plt", 0); - if(plt->size == 0) { - // The dynamic linker stores the address of the - // dynamic resolver and the DSO identifier in the two - // doublewords at the beginning of the .plt section - // before the PLT array. Reserve space for these. - plt->size = 16; - } -} - -int -machoreloc1(Reloc *r, vlong sectoff) -{ - USED(r); - USED(sectoff); - - return -1; -} - -// Return the value of .TOC. for symbol s -static vlong -symtoc(LSym *s) -{ - LSym *toc; - - if(s->outer != nil) - toc = linkrlookup(ctxt, ".TOC.", s->outer->version); - else - toc = linkrlookup(ctxt, ".TOC.", s->version); - - if(toc == nil) { - diag("TOC-relative relocation in object without .TOC."); - return 0; - } - return toc->value; -} - -int -archreloc(Reloc *r, LSym *s, vlong *val) -{ - uint32 o1, o2; - vlong t; - - if(linkmode == LinkExternal) { - // TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations. - // R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO. - // R_CALLPOWER corresponds to R_PPC_REL24. - return -1; - } - switch(r->type) { - case R_CONST: - *val = r->add; - return 0; - case R_GOTOFF: - *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); - return 0; - case R_ADDRPOWER: - // r->add is two ppc64 instructions holding an immediate 32-bit constant. - // We want to add r->sym's address to that constant. - // The encoding of the immediate x<<16 + y, - // where x is the low 16 bits of the first instruction and y is the low 16 - // bits of the second. Both x and y are signed (int16, not uint16). - o1 = r->add >> 32; - o2 = r->add; - t = symaddr(r->sym); - if(t < 0) { - ctxt->diag("relocation for %s is too big (>=2G): %lld", s->name, symaddr(r->sym)); - } - t += ((o1 & 0xffff) << 16) + ((int32)o2 << 16 >> 16); - if(t & 0x8000) - t += 0x10000; - o1 = (o1 & 0xffff0000) | ((t >> 16) & 0xffff); - o2 = (o2 & 0xffff0000) | (t & 0xffff); - // when laid out, the instruction order must always be o1, o2. - if(ctxt->arch->endian == BigEndian) - *val = ((vlong)o1 << 32) | o2; - else - *val = ((vlong)o2 << 32) | o1; - return 0; - case R_CALLPOWER: - // Bits 6 through 29 = (S + A - P) >> 2 - if(ctxt->arch->endian == BigEndian) - o1 = be32(s->p + r->off); - else - o1 = le32(s->p + r->off); - - t = symaddr(r->sym) + r->add - (s->value + r->off); - if(t & 3) - ctxt->diag("relocation for %s+%d is not aligned: %lld", r->sym->name, r->off, t); - if((int32)(t << 6) >> 6 != t) - // TODO(austin) This can happen if text > 32M. - // Add a call trampoline to .text in that case. - ctxt->diag("relocation for %s+%d is too big: %lld", r->sym->name, r->off, t); - - *val = (o1 & 0xfc000003U) | (t & ~0xfc000003U); - return 0; - case R_POWER_TOC: // S + A - .TOC. - *val = symaddr(r->sym) + r->add - symtoc(s); - return 0; - } - return -1; -} - -vlong -archrelocvariant(Reloc *r, LSym *s, vlong t) -{ - uint32 o1; - switch(r->variant & RV_TYPE_MASK) { - default: - diag("unexpected relocation variant %d", r->variant); - - case RV_NONE: - return t; - - case RV_POWER_LO: - if(r->variant & RV_CHECK_OVERFLOW) { - // Whether to check for signed or unsigned - // overflow depends on the instruction - if(ctxt->arch->endian == BigEndian) - o1 = be32(s->p + r->off - 2); - else - o1 = le32(s->p + r->off); - switch(o1 >> 26) { - case 24: // ori - case 26: // xori - case 28: // andi - if((t >> 16) != 0) - goto overflow; - break; - default: - if((int16)t != t) - goto overflow; - break; - } - } - return (int16)t; - - case RV_POWER_HA: - t += 0x8000; - // Fallthrough - case RV_POWER_HI: - t >>= 16; - if(r->variant & RV_CHECK_OVERFLOW) { - // Whether to check for signed or unsigned - // overflow depends on the instruction - if(ctxt->arch->endian == BigEndian) - o1 = be32(s->p + r->off - 2); - else - o1 = le32(s->p + r->off); - switch(o1 >> 26) { - case 25: // oris - case 27: // xoris - case 29: // andis - if((t >> 16) != 0) - goto overflow; - break; - default: - if((int16)t != t) - goto overflow; - break; - } - } - return (int16)t; - - case RV_POWER_DS: - if(ctxt->arch->endian == BigEndian) - o1 = be16(s->p + r->off); - else - o1 = le16(s->p + r->off); - if(t & 3) - diag("relocation for %s+%d is not aligned: %lld", r->sym->name, r->off, t); - if((r->variant & RV_CHECK_OVERFLOW) && (int16)t != t) - goto overflow; - return (o1 & 0x3) | (vlong)(int16)t; - } - -overflow: - diag("relocation for %s+%d is too big: %lld", r->sym->name, r->off, t); - return t; -} - -static void -addpltsym(Link *ctxt, LSym *s) -{ - if(s->plt >= 0) - return; - - adddynsym(ctxt, s); - - if(iself) { - LSym *plt, *rela, *glink; - Reloc *r; - - plt = linklookup(ctxt, ".plt", 0); - rela = linklookup(ctxt, ".rela.plt", 0); - if(plt->size == 0) - elfsetupplt(); - - // Create the glink resolver if necessary - glink = ensureglinkresolver(); - - // Write symbol resolver stub (just a branch to the - // glink resolver stub) - r = addrel(glink); - r->sym = glink; - r->off = glink->size; - r->siz = 4; - r->type = R_CALLPOWER; - adduint32(ctxt, glink, 0x48000000); // b .glink - - // In the ppc64 ABI, the dynamic linker is responsible - // for writing the entire PLT. We just need to - // reserve 8 bytes for each PLT entry and generate a - // JMP_SLOT dynamic relocation for it. - // - // TODO(austin): ABI v1 is different - s->plt = plt->size; - plt->size += 8; - - addaddrplus(ctxt, rela, plt, s->plt); - adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_PPC64_JMP_SLOT)); - adduint64(ctxt, rela, 0); - } else { - diag("addpltsym: unsupported binary format"); - } -} - -// Generate the glink resolver stub if necessary and return the .glink section -static LSym* -ensureglinkresolver(void) -{ - LSym *glink, *s; - Reloc *r; - - glink = linklookup(ctxt, ".glink", 0); - if(glink->size != 0) - return glink; - - // This is essentially the resolver from the ppc64 ELF ABI. - // At entry, r12 holds the address of the symbol resolver stub - // for the target routine and the argument registers hold the - // arguments for the target routine. - // - // This stub is PIC, so first get the PC of label 1 into r11. - // Other things will be relative to this. - adduint32(ctxt, glink, 0x7c0802a6); // mflr r0 - adduint32(ctxt, glink, 0x429f0005); // bcl 20,31,1f - adduint32(ctxt, glink, 0x7d6802a6); // 1: mflr r11 - adduint32(ctxt, glink, 0x7c0803a6); // mtlf r0 - - // Compute the .plt array index from the entry point address. - // Because this is PIC, everything is relative to label 1b (in - // r11): - // r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4 - adduint32(ctxt, glink, 0x3800ffd0); // li r0,-(res_0-1b)=-48 - adduint32(ctxt, glink, 0x7c006214); // add r0,r0,r12 - adduint32(ctxt, glink, 0x7c0b0050); // sub r0,r0,r11 - adduint32(ctxt, glink, 0x7800f082); // srdi r0,r0,2 - - // r11 = address of the first byte of the PLT - r = addrel(glink); - r->off = glink->size; - r->sym = linklookup(ctxt, ".plt", 0); - r->siz = 8; - r->type = R_ADDRPOWER; - // addis r11,0,.plt@ha; addi r11,r11,.plt@l - r->add = (0x3d600000ull << 32) | 0x396b0000; - glink->size += 8; - - // Load r12 = dynamic resolver address and r11 = DSO - // identifier from the first two doublewords of the PLT. - adduint32(ctxt, glink, 0xe98b0000); // ld r12,0(r11) - adduint32(ctxt, glink, 0xe96b0008); // ld r11,8(r11) - - // Jump to the dynamic resolver - adduint32(ctxt, glink, 0x7d8903a6); // mtctr r12 - adduint32(ctxt, glink, 0x4e800420); // bctr - - // The symbol resolvers must immediately follow. - // res_0: - - // Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes - // before the first symbol resolver stub. - s = linklookup(ctxt, ".dynamic", 0); - elfwritedynentsymplus(s, DT_PPC64_GLINK, glink, glink->size - 32); - - return glink; -} - -void -adddynsym(Link *ctxt, LSym *s) -{ - LSym *d; - int t; - char *name; - - if(s->dynid >= 0) - return; - - if(iself) { - s->dynid = nelfsym++; - - d = linklookup(ctxt, ".dynsym", 0); - - name = s->extname; - adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); - - /* type */ - t = STB_GLOBAL << 4; - if(s->cgoexport && (s->type&SMASK) == STEXT) - t |= STT_FUNC; - else - t |= STT_OBJECT; - adduint8(ctxt, d, t); - - /* reserved */ - adduint8(ctxt, d, 0); - - /* section where symbol is defined */ - if(s->type == SDYNIMPORT) - adduint16(ctxt, d, SHN_UNDEF); - else - adduint16(ctxt, d, 1); - - /* value */ - if(s->type == SDYNIMPORT) - adduint64(ctxt, d, 0); - else - addaddr(ctxt, d, s); - - /* size of object */ - adduint64(ctxt, d, s->size); - } else { - diag("adddynsym: unsupported binary format"); - } -} - -void -adddynlib(char *lib) -{ - LSym *s; - - if(!needlib(lib)) - return; - - if(iself) { - s = linklookup(ctxt, ".dynstr", 0); - if(s->size == 0) - addstring(s, ""); - elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); - } else { - diag("adddynlib: unsupported binary format"); - } -} - -void -asmb(void) -{ - uint32 symo; - Section *sect; - LSym *sym; - int i; - - if(debug['v']) - Bprint(&bso, "%5.2f asmb\n", cputime()); - Bflush(&bso); - - if(iself) - asmbelfsetup(); - - sect = segtext.sect; - cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); - codeblk(sect->vaddr, sect->length); - for(sect = sect->next; sect != nil; sect = sect->next) { - cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); - datblk(sect->vaddr, sect->length); - } - - if(segrodata.filelen > 0) { - if(debug['v']) - Bprint(&bso, "%5.2f rodatblk\n", cputime()); - Bflush(&bso); - - cseek(segrodata.fileoff); - datblk(segrodata.vaddr, segrodata.filelen); - } - - if(debug['v']) - Bprint(&bso, "%5.2f datblk\n", cputime()); - Bflush(&bso); - - cseek(segdata.fileoff); - datblk(segdata.vaddr, segdata.filelen); - - /* output symbol table */ - symsize = 0; - lcsize = 0; - symo = 0; - if(!debug['s']) { - // TODO: rationalize - if(debug['v']) - Bprint(&bso, "%5.2f sym\n", cputime()); - Bflush(&bso); - switch(HEADTYPE) { - default: - if(iself) { - symo = segdata.fileoff+segdata.filelen; - symo = rnd(symo, INITRND); - } - break; - case Hplan9: - symo = segdata.fileoff+segdata.filelen; - break; - } - cseek(symo); - switch(HEADTYPE) { - default: - if(iself) { - if(debug['v']) - Bprint(&bso, "%5.2f elfsym\n", cputime()); - asmelfsym(); - cflush(); - cwrite(elfstrdat, elfstrsize); - - if(debug['v']) - Bprint(&bso, "%5.2f dwarf\n", cputime()); - dwarfemitdebugsections(); - - if(linkmode == LinkExternal) - elfemitreloc(); - } - break; - case Hplan9: - asmplan9sym(); - cflush(); - - sym = linklookup(ctxt, "pclntab", 0); - if(sym != nil) { - lcsize = sym->np; - for(i=0; i < lcsize; i++) - cput(sym->p[i]); - - cflush(); - } - break; - } - } - - ctxt->cursym = nil; - if(debug['v']) - Bprint(&bso, "%5.2f header\n", cputime()); - Bflush(&bso); - cseek(0L); - switch(HEADTYPE) { - default: - case Hplan9: /* plan 9 */ - thearch.lput(0x647); /* magic */ - thearch.lput(segtext.filelen); /* sizes */ - thearch.lput(segdata.filelen); - thearch.lput(segdata.length - segdata.filelen); - thearch.lput(symsize); /* nsyms */ - thearch.lput(entryvalue()); /* va of entry */ - thearch.lput(0L); - thearch.lput(lcsize); - break; - case Hlinux: - case Hfreebsd: - case Hnetbsd: - case Hopenbsd: - case Hnacl: - asmbelf(symo); - break; - } - cflush(); - if(debug['c']){ - print("textsize=%ulld\n", segtext.filelen); - print("datsize=%ulld\n", segdata.filelen); - print("bsssize=%ulld\n", segdata.length - segdata.filelen); - print("symsize=%d\n", symsize); - print("lcsize=%d\n", lcsize); - print("total=%lld\n", segtext.filelen+segdata.length+symsize+lcsize); - } -} diff --git a/src/cmd/new9l/asm.go b/src/cmd/9l/asm.go similarity index 100% rename from src/cmd/new9l/asm.go rename to src/cmd/9l/asm.go diff --git a/src/cmd/9l/doc.go b/src/cmd/9l/doc.go deleted file mode 100644 index 3e3c48018d..0000000000 --- a/src/cmd/9l/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -9l is the linker for 64-bit PowerPC and Power Architecture processors. -The $GOARCH for these tools is ppc64 (big endian) or -ppc64le (little endian). - -The flags are documented in ../ld/doc.go. - -*/ -package main diff --git a/src/cmd/new9l/l.go b/src/cmd/9l/l.go similarity index 100% rename from src/cmd/new9l/l.go rename to src/cmd/9l/l.go diff --git a/src/cmd/9l/l.h b/src/cmd/9l/l.h deleted file mode 100644 index 5c048d2570..0000000000 --- a/src/cmd/9l/l.h +++ /dev/null @@ -1,65 +0,0 @@ -// cmd/9l/l.h from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include -#include - -#ifndef EXTERN -#define EXTERN extern -#endif - -enum -{ - thechar = '9', - PtrSize = 8, - IntSize = 8, - RegSize = 8, - MaxAlign = 32, // max data alignment - FuncAlign = 8, - MINLC = 4, -}; - -void adddynlib(char *lib); -void adddynrel(LSym *s, Reloc *r); -void adddynrela(LSym *rela, LSym *s, Reloc *r); -void adddynsym(Link *ctxt, LSym *s); -int archreloc(Reloc *r, LSym *s, vlong *val); -vlong archrelocvariant(Reloc *r, LSym *s, vlong t); -void asmb(void); -int elfreloc1(Reloc *r, vlong sectoff); -void elfsetupplt(void); -int machoreloc1(Reloc *r, vlong sectoff); - -/* Used by ../ld/dwarf.c */ -enum -{ - DWARFREGSP = 1 -}; diff --git a/src/cmd/9l/obj.c b/src/cmd/9l/obj.c deleted file mode 100644 index 5449319f38..0000000000 --- a/src/cmd/9l/obj.c +++ /dev/null @@ -1,151 +0,0 @@ -// Inferno utils/5l/obj.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Reading object files. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" -#include "../ld/dwarf.h" -#include - -void -main(int argc, char **argv) -{ - linkarchinit(); - ldmain(argc, argv); -} - -void -linkarchinit(void) -{ - thestring = getgoarch(); - if(strcmp(thestring, "ppc64le") == 0) - thelinkarch = &linkppc64le; - else - thelinkarch = &linkppc64; - - thearch.thechar = thechar; - thearch.ptrsize = thelinkarch->ptrsize; - thearch.intsize = thelinkarch->ptrsize; - thearch.regsize = thelinkarch->regsize; - thearch.funcalign = FuncAlign; - thearch.maxalign = MaxAlign; - thearch.minlc = MINLC; - thearch.dwarfregsp = DWARFREGSP; - - thearch.adddynlib = adddynlib; - thearch.adddynrel = adddynrel; - thearch.adddynsym = adddynsym; - thearch.archinit = archinit; - thearch.archreloc = archreloc; - thearch.archrelocvariant = archrelocvariant; - thearch.asmb = asmb; - thearch.elfreloc1 = elfreloc1; - thearch.elfsetupplt = elfsetupplt; - thearch.gentext = gentext; - thearch.machoreloc1 = machoreloc1; - if(thelinkarch == &linkppc64le) { - thearch.lput = lputl; - thearch.wput = wputl; - thearch.vput = vputl; - } else { - thearch.lput = lputb; - thearch.wput = wputb; - thearch.vput = vputb; - } - - // TODO(austin): ABI v1 uses /usr/lib/ld.so.1 - thearch.linuxdynld = "/lib64/ld64.so.1"; - thearch.freebsddynld = "XXX"; - thearch.openbsddynld = "XXX"; - thearch.netbsddynld = "XXX"; - thearch.dragonflydynld = "XXX"; - thearch.solarisdynld = "XXX"; -} - -void -archinit(void) -{ - // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when - // Go was built; see ../../make.bash. - if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) - linkmode = LinkInternal; - - switch(HEADTYPE) { - default: - if(linkmode == LinkAuto) - linkmode = LinkInternal; - if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0) - sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE)); - break; - } - - switch(HEADTYPE) { - default: - diag("unknown -H option"); - errorexit(); - case Hplan9: /* plan 9 */ - HEADR = 32L; - if(INITTEXT == -1) - INITTEXT = 4128; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; - break; - case Hlinux: /* ppc64 elf */ - if(strcmp(thestring, "ppc64") == 0) - debug['d'] = 1; // TODO(austin): ELF ABI v1 not supported yet - elfinit(); - HEADR = ELFRESERVE; - if(INITTEXT == -1) - INITTEXT = 0x10000 + HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 0x10000; - break; - case Hnacl: - elfinit(); - HEADR = 0x10000; - funcalign = 16; - if(INITTEXT == -1) - INITTEXT = 0x20000; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 0x10000; - break; - } - if(INITDAT != 0 && INITRND != 0) - print("warning: -D0x%ux is ignored because of -R0x%ux\n", - INITDAT, INITRND); -} diff --git a/src/cmd/new9l/obj.go b/src/cmd/9l/obj.go similarity index 100% rename from src/cmd/new9l/obj.go rename to src/cmd/9l/obj.go diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 00d289cf29..f21331055f 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -135,7 +135,7 @@ func xinit() { } go386 = b - p := pathf("%s/include/u.h", goroot) + p := pathf("%s/src/all.bash", goroot) if !isfile(p) { fatal("$GOROOT is not set correctly or not exported\n"+ "\tGOROOT=%s\n"+ @@ -507,50 +507,9 @@ var deptab = []struct { prefix string // prefix of target dep []string // dependency tweaks for targets with that prefix }{ - {"lib9", []string{ - "$GOROOT/include/u.h", - "$GOROOT/include/utf.h", - "$GOROOT/include/fmt.h", - "$GOROOT/include/libc.h", - "fmt/*", - "utf/*", - }}, - {"libbio", []string{ - "$GOROOT/include/u.h", - "$GOROOT/include/utf.h", - "$GOROOT/include/fmt.h", - "$GOROOT/include/libc.h", - "$GOROOT/include/bio.h", - }}, - {"liblink", []string{ - "$GOROOT/include/u.h", - "$GOROOT/include/utf.h", - "$GOROOT/include/fmt.h", - "$GOROOT/include/libc.h", - "$GOROOT/include/bio.h", - "$GOROOT/include/ar.h", - "$GOROOT/include/link.h", - }}, - {"cmd/5l", []string{ - "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a", - }}, - {"cmd/6l", []string{ - "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a", - }}, - {"cmd/8l", []string{ - "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a", - }}, - {"cmd/9l", []string{ - "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a", - }}, {"cmd/go", []string{ "zdefaultcc.go", }}, - {"cmd/", []string{ - "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/liblink.a", - "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libbio.a", - "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/lib9.a", - }}, {"runtime", []string{ "zversion.go", }}, @@ -635,11 +594,6 @@ func install(dir string) { case "lib9", "libbio", "liblink", "cmd/gc", "cmd/ld": islib = true isgo = false - case "cmd/5l", - "cmd/6l", - "cmd/8l", - "cmd/9l": - isgo = false } // Start final link command line. @@ -800,7 +754,7 @@ func install(dir string) { if dir == "runtime" { // For use by assembly and C files. copyfile(pathf("%s/pkg/%s_%s/textflag.h", goroot, goos, goarch), - pathf("%s/src/cmd/ld/textflag.h", goroot), 0) + pathf("%s/src/runtime/textflag.h", goroot), 0) copyfile(pathf("%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch), pathf("%s/src/runtime/funcdata.h", goroot), 0) } @@ -1109,13 +1063,6 @@ func dopack(dst, src string, extra []string) { // The Go packages and commands must be in dependency order, // maintained by hand, but the order doesn't change often. var buildorder = []string{ - // Legacy C programs. - "lib9", - "libbio", - "liblink", - "cmd/ld", // must be before l - "cmd/%sl", // must be before a, g - // Go libraries and programs for bootstrap. "runtime", "errors", diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go index 1b4f429730..d8192f6736 100644 --- a/src/cmd/dist/buildtool.go +++ b/src/cmd/dist/buildtool.go @@ -25,12 +25,16 @@ import ( var bootstrapDirs = []string{ "5a", "5g", + "5l", "6a", "6g", + "6l", "8a", "8g", + "8l", "9a", "9g", + "9l", "asm", "asm/internal/arch", "asm/internal/asm", @@ -44,10 +48,6 @@ var bootstrapDirs = []string{ "internal/obj/i386", "internal/obj/ppc64", "internal/obj/x86", - "new5l", - "new6l", - "new8l", - "new9l", } func bootstrapBuildTools() { diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 784c751def..292bc73003 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1892,7 +1892,7 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, } } ldflags = append(ldflags, buildLdflags...) - return b.run(".", p.ImportPath, nil, buildToolExec, tool("new"+archChar+"l"), "-o", out, importArgs, ldflags, mainpkg) + return b.run(".", p.ImportPath, nil, buildToolExec, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg) } func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index 39be2c0c15..d303d7f811 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -393,12 +393,16 @@ const ( var goTools = map[string]targetDir{ "cmd/5a": toTool, "cmd/5g": toTool, + "cmd/5l": toTool, "cmd/6a": toTool, "cmd/6g": toTool, + "cmd/6l": toTool, "cmd/8a": toTool, "cmd/8g": toTool, + "cmd/8l": toTool, "cmd/9a": toTool, "cmd/9g": toTool, + "cmd/9l": toTool, "cmd/addr2line": toTool, "cmd/api": toTool, "cmd/asm": toTool, @@ -406,10 +410,6 @@ var goTools = map[string]targetDir{ "cmd/dist": toTool, "cmd/fix": toTool, "cmd/link": toTool, - "cmd/new5l": toTool, - "cmd/new6l": toTool, - "cmd/new8l": toTool, - "cmd/new9l": toTool, "cmd/nm": toTool, "cmd/objdump": toTool, "cmd/pack": toTool, diff --git a/src/cmd/ld/Makefile b/src/cmd/ld/Makefile deleted file mode 100644 index 3f528d7517..0000000000 --- a/src/cmd/ld/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c deleted file mode 100644 index c03946318c..0000000000 --- a/src/cmd/ld/data.c +++ /dev/null @@ -1,1460 +0,0 @@ -// Inferno utils/8l/asm.c -// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Data layout and relocation. - -#include -#include -#include -#include -#include "lib.h" -#include "elf.h" -#include "macho.h" -#include "pe.h" -#include "../../runtime/mgc0.h" - -void dynreloc(void); - -/* - * divide-and-conquer list-link - * sort of LSym* structures. - * Used for the data block. - */ -int -datcmp(LSym *s1, LSym *s2) -{ - if(s1->type != s2->type) - return (int)s1->type - (int)s2->type; - // For ppc64, we want to interleave the .got and .toc sections - // from input files. Both are type SELFGOT, so in that case - // fall through to the name comparison (conveniently, .got - // sorts before .toc). - if(s1->type != SELFGOT && s1->size != s2->size) { - if(s1->size < s2->size) - return -1; - return +1; - } - return strcmp(s1->name, s2->name); -} - -LSym** -listnextp(LSym *s) -{ - return &s->next; -} - -LSym** -listsubp(LSym *s) -{ - return &s->sub; -} - -LSym* -listsort(LSym *l, int (*cmp)(LSym*, LSym*), LSym **(*nextp)(LSym*)) -{ - LSym *l1, *l2, *le; - - if(l == 0 || *nextp(l) == 0) - return l; - - l1 = l; - l2 = l; - for(;;) { - l2 = *nextp(l2); - if(l2 == 0) - break; - l2 = *nextp(l2); - if(l2 == 0) - break; - l1 = *nextp(l1); - } - - l2 = *nextp(l1); - *nextp(l1) = 0; - l1 = listsort(l, cmp, nextp); - l2 = listsort(l2, cmp, nextp); - - /* set up lead element */ - if(cmp(l1, l2) < 0) { - l = l1; - l1 = *nextp(l1); - } else { - l = l2; - l2 = *nextp(l2); - } - le = l; - - for(;;) { - if(l1 == 0) { - while(l2) { - *nextp(le) = l2; - le = l2; - l2 = *nextp(l2); - } - *nextp(le) = 0; - break; - } - if(l2 == 0) { - while(l1) { - *nextp(le) = l1; - le = l1; - l1 = *nextp(l1); - } - break; - } - if(cmp(l1, l2) < 0) { - *nextp(le) = l1; - le = l1; - l1 = *nextp(l1); - } else { - *nextp(le) = l2; - le = l2; - l2 = *nextp(l2); - } - } - *nextp(le) = 0; - return l; -} - -void -relocsym(LSym *s) -{ - Reloc *r; - LSym *rs; - int16 i16; - int32 i, ri, off, siz, fl; - vlong o; - uchar *cast; - - ctxt->cursym = s; - for(ri=0; rinr; ri++) { - r = &s->r[ri]; - r->done = 1; - off = r->off; - siz = r->siz; - if(off < 0 || off+siz > s->np) { - diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np); - continue; - } - if(r->sym != nil && ((r->sym->type & (SMASK | SHIDDEN)) == 0 || (r->sym->type & SMASK) == SXREF)) { - diag("%s: not defined", r->sym->name); - continue; - } - if(r->type >= 256) - continue; - if(r->siz == 0) // informational relocation - no work to do - continue; - - // Solaris needs the ability to reference dynimport symbols. - if(HEADTYPE != Hsolaris && r->sym != nil && r->sym->type == SDYNIMPORT) - diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type); - if(r->sym != nil && r->sym->type != STLSBSS && !r->sym->reachable) - diag("unreachable sym in relocation: %s %s", s->name, r->sym->name); - - // Android emulates runtime.tlsg as a regular variable. - if (r->type == R_TLS && strcmp(goos, "android") == 0) - r->type = R_ADDR; - - switch(r->type) { - default: - o = 0; - if(thearch.archreloc(r, s, &o) < 0) - diag("unknown reloc %d", r->type); - break; - case R_TLS: - if(linkmode == LinkInternal && iself && thearch.thechar == '5') { - // On ELF ARM, the thread pointer is 8 bytes before - // the start of the thread-local data block, so add 8 - // to the actual TLS offset (r->sym->value). - // This 8 seems to be a fundamental constant of - // ELF on ARM (or maybe Glibc on ARM); it is not - // related to the fact that our own TLS storage happens - // to take up 8 bytes. - o = 8 + r->sym->value; - break; - } - r->done = 0; - o = 0; - if(thearch.thechar != '6') - o = r->add; - break; - case R_TLS_LE: - if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { - r->done = 0; - r->sym = ctxt->tlsg; - r->xsym = ctxt->tlsg; - r->xadd = r->add; - o = 0; - if(thearch.thechar != '6') - o = r->add; - break; - } - o = ctxt->tlsoffset + r->add; - break; - - case R_TLS_IE: - if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { - r->done = 0; - r->sym = ctxt->tlsg; - r->xsym = ctxt->tlsg; - r->xadd = r->add; - o = 0; - if(thearch.thechar != '6') - o = r->add; - break; - } - if(iself || ctxt->headtype == Hplan9) - o = ctxt->tlsoffset + r->add; - else if(ctxt->headtype == Hwindows) - o = r->add; - else - sysfatal("unexpected R_TLS_IE relocation for %s", headstr(ctxt->headtype)); - break; - case R_ADDR: - if(linkmode == LinkExternal && r->sym->type != SCONST) { - r->done = 0; - - // set up addend for eventual relocation via outer symbol. - rs = r->sym; - r->xadd = r->add; - while(rs->outer != nil) { - r->xadd += symaddr(rs) - symaddr(rs->outer); - rs = rs->outer; - } - if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil) - diag("missing section for %s", rs->name); - r->xsym = rs; - - o = r->xadd; - if(iself) { - if(thearch.thechar == '6') - o = 0; - } else if(HEADTYPE == Hdarwin) { - if(rs->type != SHOSTOBJ) - o += symaddr(rs); - } else { - diag("unhandled pcrel relocation for %s", headstring); - } - break; - } - o = symaddr(r->sym) + r->add; - - // On amd64, 4-byte offsets will be sign-extended, so it is impossible to - // access more than 2GB of static data; fail at link time is better than - // fail at runtime. See http://golang.org/issue/7980. - // Instead of special casing only amd64, we treat this as an error on all - // 64-bit architectures so as to be future-proof. - if((int32)o < 0 && thearch.ptrsize > 4 && siz == 4) { - diag("non-pc-relative relocation address is too big: %#llux", o); - errorexit(); - } - break; - case R_CALL: - case R_PCREL: - // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. - if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != ctxt->cursym->sect) { - r->done = 0; - - // set up addend for eventual relocation via outer symbol. - rs = r->sym; - r->xadd = r->add; - while(rs->outer != nil) { - r->xadd += symaddr(rs) - symaddr(rs->outer); - rs = rs->outer; - } - r->xadd -= r->siz; // relative to address after the relocated chunk - if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil) - diag("missing section for %s", rs->name); - r->xsym = rs; - - o = r->xadd; - if(iself) { - if(thearch.thechar == '6') - o = 0; - } else if(HEADTYPE == Hdarwin) { - if(r->type == R_CALL) { - if(rs->type != SHOSTOBJ) - o += symaddr(rs) - ((Section*)rs->sect)->vaddr; - o -= r->off; // relative to section offset, not symbol - } else { - o += r->siz; - } - } else { - diag("unhandled pcrel relocation for %s", headstring); - } - break; - } - o = 0; - if(r->sym) - o += symaddr(r->sym); - // NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c - // compiler. The expression s->value + r->off + r->siz is int32 + int32 + - // uchar, and Plan 9 8c incorrectly treats the expression as type uint32 - // instead of int32, causing incorrect values when sign extended for adding - // to o. The bug only occurs on Plan 9, because this C program is compiled by - // the standard host compiler (gcc on most other systems). - o += r->add - (s->value + r->off + (int32)r->siz); - break; - case R_SIZE: - o = r->sym->size + r->add; - break; - } - if(r->variant != RV_NONE) - o = thearch.archrelocvariant(r, s, o); -//print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o); - switch(siz) { - default: - ctxt->cursym = s; - diag("bad reloc size %#ux for %s", siz, r->sym->name); - case 1: - // TODO(rsc): Remove. - s->p[off] = (int8)o; - break; - case 2: - if(o != (int16)o) - diag("relocation address is too big: %#llx", o); - i16 = o; - cast = (uchar*)&i16; - for(i=0; i<2; i++) - s->p[off+i] = cast[inuxi2[i]]; - break; - case 4: - if(r->type == R_PCREL || r->type == R_CALL) { - if(o != (int32)o) - diag("pc-relative relocation address is too big: %#llx", o); - } else { - if(o != (int32)o && o != (uint32)o) - diag("non-pc-relative relocation address is too big: %#llux", o); - } - fl = o; - cast = (uchar*)&fl; - for(i=0; i<4; i++) - s->p[off+i] = cast[inuxi4[i]]; - break; - case 8: - cast = (uchar*)&o; - for(i=0; i<8; i++) - s->p[off+i] = cast[inuxi8[i]]; - break; - } - } -} - -void -reloc(void) -{ - LSym *s; - - if(debug['v']) - Bprint(&bso, "%5.2f reloc\n", cputime()); - Bflush(&bso); - - for(s=ctxt->textp; s!=nil; s=s->next) - relocsym(s); - for(s=datap; s!=nil; s=s->next) - relocsym(s); -} - -void -dynrelocsym(LSym *s) -{ - int ri; - Reloc *r; - - if(HEADTYPE == Hwindows) { - LSym *rel, *targ; - - rel = linklookup(ctxt, ".rel", 0); - if(s == rel) - return; - for(ri=0; rinr; ri++) { - r = &s->r[ri]; - targ = r->sym; - if(targ == nil) - continue; - if(!targ->reachable) - diag("internal inconsistency: dynamic symbol %s is not reachable.", targ->name); - if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files. - targ->plt = rel->size; - r->sym = rel; - r->add = targ->plt; - - // jmp *addr - if(thearch.thechar == '8') { - adduint8(ctxt, rel, 0xff); - adduint8(ctxt, rel, 0x25); - addaddr(ctxt, rel, targ); - adduint8(ctxt, rel, 0x90); - adduint8(ctxt, rel, 0x90); - } else { - adduint8(ctxt, rel, 0xff); - adduint8(ctxt, rel, 0x24); - adduint8(ctxt, rel, 0x25); - addaddrplus4(ctxt, rel, targ, 0); - adduint8(ctxt, rel, 0x90); - } - } else if(r->sym->plt >= 0) { - r->sym = rel; - r->add = targ->plt; - } - } - return; - } - - for(ri=0; rinr; ri++) { - r = &s->r[ri]; - if(r->sym != nil && r->sym->type == SDYNIMPORT || r->type >= 256) { - if(r->sym != nil && !r->sym->reachable) - diag("internal inconsistency: dynamic symbol %s is not reachable.", r->sym->name); - thearch.adddynrel(s, r); - } - } -} - -void -dynreloc(void) -{ - LSym *s; - - // -d suppresses dynamic loader format, so we may as well not - // compute these sections or mark their symbols as reachable. - if(debug['d'] && HEADTYPE != Hwindows) - return; - if(debug['v']) - Bprint(&bso, "%5.2f reloc\n", cputime()); - Bflush(&bso); - - for(s=ctxt->textp; s!=nil; s=s->next) - dynrelocsym(s); - for(s=datap; s!=nil; s=s->next) - dynrelocsym(s); - if(iself) - elfdynhash(); -} - -static void -blk(LSym *start, int64 addr, int64 size) -{ - LSym *sym; - int64 eaddr; - uchar *p, *ep; - - for(sym = start; sym != nil; sym = sym->next) - if(!(sym->type&SSUB) && sym->value >= addr) - break; - - eaddr = addr+size; - for(; sym != nil; sym = sym->next) { - if(sym->type&SSUB) - continue; - if(sym->value >= eaddr) - break; - ctxt->cursym = sym; - if(sym->value < addr) { - diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type); - errorexit(); - } - for(; addr < sym->value; addr++) - cput(0); - p = sym->p; - ep = p + sym->np; - while(p < ep) - cput(*p++); - addr += sym->np; - for(; addr < sym->value+sym->size; addr++) - cput(0); - if(addr != sym->value+sym->size) { - diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size); - errorexit(); - } - if(sym->value+sym->size >= eaddr) - break; - } - - for(; addr < eaddr; addr++) - cput(0); - cflush(); -} - -void -codeblk(int64 addr, int64 size) -{ - LSym *sym; - int64 eaddr, n; - uchar *q; - - if(debug['a']) - Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); - - blk(ctxt->textp, addr, size); - - /* again for printing */ - if(!debug['a']) - return; - - for(sym = ctxt->textp; sym != nil; sym = sym->next) { - if(!sym->reachable) - continue; - if(sym->value >= addr) - break; - } - - eaddr = addr + size; - for(; sym != nil; sym = sym->next) { - if(!sym->reachable) - continue; - if(sym->value >= eaddr) - break; - - if(addr < sym->value) { - Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); - for(; addr < sym->value; addr++) - Bprint(&bso, " %.2ux", 0); - Bprint(&bso, "\n"); - } - - Bprint(&bso, "%.6llux\t%-20s\n", (vlong)addr, sym->name); - n = sym->size; - q = sym->p; - - while(n >= 16) { - Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q); - addr += 16; - q += 16; - n -= 16; - } - if(n > 0) - Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q); - addr += n; - } - - if(addr < eaddr) { - Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); - for(; addr < eaddr; addr++) - Bprint(&bso, " %.2ux", 0); - } - Bflush(&bso); -} - -void -datblk(int64 addr, int64 size) -{ - LSym *sym; - int64 i, eaddr; - uchar *p, *ep; - char *typ, *rsname; - Reloc *r; - - if(debug['a']) - Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); - - blk(datap, addr, size); - - /* again for printing */ - if(!debug['a']) - return; - - for(sym = datap; sym != nil; sym = sym->next) - if(sym->value >= addr) - break; - - eaddr = addr + size; - for(; sym != nil; sym = sym->next) { - if(sym->value >= eaddr) - break; - if(addr < sym->value) { - Bprint(&bso, "\t%.8ux| 00 ...\n", addr); - addr = sym->value; - } - Bprint(&bso, "%s\n\t%.8ux|", sym->name, (uint)addr); - p = sym->p; - ep = p + sym->np; - while(p < ep) { - if(p > sym->p && (int)(p-sym->p)%16 == 0) - Bprint(&bso, "\n\t%.8ux|", (uint)(addr+(p-sym->p))); - Bprint(&bso, " %.2ux", *p++); - } - addr += sym->np; - for(; addr < sym->value+sym->size; addr++) - Bprint(&bso, " %.2ux", 0); - Bprint(&bso, "\n"); - - if(linkmode == LinkExternal) { - for(i=0; inr; i++) { - r = &sym->r[i]; - rsname = ""; - if(r->sym) - rsname = r->sym->name; - typ = "?"; - switch(r->type) { - case R_ADDR: - typ = "addr"; - break; - case R_PCREL: - typ = "pcrel"; - break; - case R_CALL: - typ = "call"; - break; - } - Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n", - (uint)(sym->value+r->off), r->siz, typ, rsname, (vlong)r->add, (vlong)(r->sym->value+r->add)); - } - } - } - - if(addr < eaddr) - Bprint(&bso, "\t%.8ux| 00 ...\n", (uint)addr); - Bprint(&bso, "\t%.8ux|\n", (uint)eaddr); -} - -void -strnput(char *s, int n) -{ - for(; n > 0 && *s; s++) { - cput(*s); - n--; - } - while(n > 0) { - cput(0); - n--; - } -} - -void -addstrdata(char *name, char *value) -{ - LSym *s, *sp; - char *p; - uchar reachable; - - p = smprint("%s.str", name); - sp = linklookup(ctxt, p, 0); - free(p); - addstring(sp, value); - sp->type = SRODATA; - - s = linklookup(ctxt, name, 0); - s->size = 0; - s->dupok = 1; - reachable = s->reachable; - addaddr(ctxt, s, sp); - adduintxx(ctxt, s, strlen(value), thearch.ptrsize); - - // addstring, addaddr, etc., mark the symbols as reachable. - // In this case that is not necessarily true, so stick to what - // we know before entering this function. - s->reachable = reachable; - sp->reachable = reachable; -} - -vlong -addstring(LSym *s, char *str) -{ - int n; - int32 r; - - if(s->type == 0) - s->type = SNOPTRDATA; - s->reachable = 1; - r = s->size; - n = strlen(str)+1; - if(strcmp(s->name, ".shstrtab") == 0) - elfsetstring(str, r); - symgrow(ctxt, s, r+n); - memmove(s->p+r, str, n); - s->size += n; - return r; -} - -void -dosymtype(void) -{ - LSym *s; - - for(s = ctxt->allsym; s != nil; s = s->allsym) { - if(s->np > 0) { - if(s->type == SBSS) - s->type = SDATA; - if(s->type == SNOPTRBSS) - s->type = SNOPTRDATA; - } - } -} - -static int32 -symalign(LSym *s) -{ - int32 align; - - if(s->align != 0) - return s->align; - - align = thearch.maxalign; - while(align > s->size && align > 1) - align >>= 1; - if(align < s->align) - align = s->align; - return align; -} - -static vlong -aligndatsize(vlong datsize, LSym *s) -{ - return rnd(datsize, symalign(s)); -} - -// maxalign returns the maximum required alignment for -// the list of symbols s; the list stops when s->type exceeds type. -static int32 -maxalign(LSym *s, int type) -{ - int32 align, max; - - max = 0; - for(; s != nil && s->type <= type; s = s->next) { - align = symalign(s); - if(max < align) - max = align; - } - return max; -} - -// Helper object for building GC type programs. -typedef struct ProgGen ProgGen; -struct ProgGen -{ - LSym* s; - int32 datasize; - uint8 data[256/PointersPerByte]; - vlong pos; -}; - -static void -proggeninit(ProgGen *g, LSym *s) -{ - g->s = s; - g->datasize = 0; - g->pos = 0; - memset(g->data, 0, sizeof(g->data)); -} - -static void -proggenemit(ProgGen *g, uint8 v) -{ - adduint8(ctxt, g->s, v); -} - -// Writes insData block from g->data. -static void -proggendataflush(ProgGen *g) -{ - int32 i, s; - - if(g->datasize == 0) - return; - proggenemit(g, insData); - proggenemit(g, g->datasize); - s = (g->datasize + PointersPerByte - 1)/PointersPerByte; - for(i = 0; i < s; i++) - proggenemit(g, g->data[i]); - g->datasize = 0; - memset(g->data, 0, sizeof(g->data)); -} - -static void -proggendata(ProgGen *g, uint8 d) -{ - g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer); - g->datasize++; - if(g->datasize == 255) - proggendataflush(g); -} - -// Skip v bytes due to alignment, etc. -static void -proggenskip(ProgGen *g, vlong off, vlong v) -{ - vlong i; - - for(i = off; i < off+v; i++) { - if((i%thearch.ptrsize) == 0) - proggendata(g, BitsScalar); - } -} - -// Emit insArray instruction. -static void -proggenarray(ProgGen *g, vlong length) -{ - int32 i; - - proggendataflush(g); - proggenemit(g, insArray); - for(i = 0; i < thearch.ptrsize; i++, length >>= 8) - proggenemit(g, length); -} - -static void -proggenarrayend(ProgGen *g) -{ - proggendataflush(g); - proggenemit(g, insArrayEnd); -} - -static void -proggenfini(ProgGen *g, vlong size) -{ - proggenskip(g, g->pos, size - g->pos); - proggendataflush(g); - proggenemit(g, insEnd); -} - - -// This function generates GC pointer info for global variables. -static void -proggenaddsym(ProgGen *g, LSym *s) -{ - LSym *gcprog; - uint8 *mask; - vlong i, size; - - if(s->size == 0) - return; - - // Skip alignment hole from the previous symbol. - proggenskip(g, g->pos, s->value - g->pos); - g->pos += s->value - g->pos; - - // The test for names beginning with . here is meant - // to keep .dynamic and .dynsym from turning up as - // conservative symbols. They should be marked SELFSECT - // and not SDATA, but sometimes that doesn't happen. - // Leave debugging the SDATA issue for the Go rewrite. - - if(s->gotype == nil && s->size >= thearch.ptrsize && s->name[0] != '.') { - // conservative scan - diag("missing Go type information for global symbol: %s size %d", s->name, (int)s->size); - if((s->size%thearch.ptrsize) || (g->pos%thearch.ptrsize)) - diag("proggenaddsym: unaligned conservative symbol %s: size=%lld pos=%lld", - s->name, s->size, g->pos); - size = (s->size+thearch.ptrsize-1)/thearch.ptrsize*thearch.ptrsize; - if(size < 32*thearch.ptrsize) { - // Emit small symbols as data. - for(i = 0; i < size/thearch.ptrsize; i++) - proggendata(g, BitsPointer); - } else { - // Emit large symbols as array. - proggenarray(g, size/thearch.ptrsize); - proggendata(g, BitsPointer); - proggenarrayend(g); - } - g->pos = s->value + size; - } else if(s->gotype == nil || decodetype_noptr(s->gotype) || s->size < thearch.ptrsize || s->name[0] == '.') { - // no scan - if(s->size < 32*thearch.ptrsize) { - // Emit small symbols as data. - // This case also handles unaligned and tiny symbols, so tread carefully. - for(i = s->value; i < s->value+s->size; i++) { - if((i%thearch.ptrsize) == 0) - proggendata(g, BitsScalar); - } - } else { - // Emit large symbols as array. - if((s->size%thearch.ptrsize) || (g->pos%thearch.ptrsize)) - diag("proggenaddsym: unaligned noscan symbol %s: size=%lld pos=%lld", - s->name, s->size, g->pos); - proggenarray(g, s->size/thearch.ptrsize); - proggendata(g, BitsScalar); - proggenarrayend(g); - } - g->pos = s->value + s->size; - } else if(decodetype_usegcprog(s->gotype)) { - // gc program, copy directly - proggendataflush(g); - gcprog = decodetype_gcprog(s->gotype); - size = decodetype_size(s->gotype); - if((size%thearch.ptrsize) || (g->pos%thearch.ptrsize)) - diag("proggenaddsym: unaligned gcprog symbol %s: size=%lld pos=%lld", - s->name, s->size, g->pos); - for(i = 0; i < gcprog->np-1; i++) - proggenemit(g, gcprog->p[i]); - g->pos = s->value + size; - } else { - // gc mask, it's small so emit as data - mask = decodetype_gcmask(s->gotype); - size = decodetype_size(s->gotype); - if((size%thearch.ptrsize) || (g->pos%thearch.ptrsize)) - diag("proggenaddsym: unaligned gcmask symbol %s: size=%lld pos=%lld", - s->name, s->size, g->pos); - for(i = 0; i < size; i += thearch.ptrsize) - proggendata(g, (mask[i/thearch.ptrsize/2]>>((i/thearch.ptrsize%2)*4+2))&BitsMask); - g->pos = s->value + size; - } -} - -void -growdatsize(vlong *datsizep, LSym *s) -{ - vlong datsize; - - datsize = *datsizep; - if(s->size < 0) - diag("negative size (datsize = %lld, s->size = %lld)", datsize, s->size); - if(datsize + s->size < datsize) - diag("symbol too large (datsize = %lld, s->size = %lld)", datsize, s->size); - *datsizep = datsize + s->size; -} - -void -dodata(void) -{ - int32 n; - vlong datsize; - Section *sect; - Segment *segro; - LSym *s, *last, **l, *toc; - LSym *gcdata, *gcbss; - ProgGen gen; - - if(debug['v']) - Bprint(&bso, "%5.2f dodata\n", cputime()); - Bflush(&bso); - - last = nil; - datap = nil; - - for(s=ctxt->allsym; s!=nil; s=s->allsym) { - if(!s->reachable || s->special) - continue; - if(STEXT < s->type && s->type < SXREF) { - if(s->onlist) - sysfatal("symbol %s listed multiple times", s->name); - s->onlist = 1; - if(last == nil) - datap = s; - else - last->next = s; - s->next = nil; - last = s; - } - } - - for(s = datap; s != nil; s = s->next) { - if(s->np > s->size) - diag("%s: initialize bounds (%lld < %d)", - s->name, (vlong)s->size, s->np); - } - - - /* - * now that we have the datap list, but before we start - * to assign addresses, record all the necessary - * dynamic relocations. these will grow the relocation - * symbol, which is itself data. - * - * on darwin, we need the symbol table numbers for dynreloc. - */ - if(HEADTYPE == Hdarwin) - machosymorder(); - dynreloc(); - - /* some symbols may no longer belong in datap (Mach-O) */ - for(l=&datap; (s=*l) != nil; ) { - if(s->type <= STEXT || SXREF <= s->type) - *l = s->next; - else - l = &s->next; - } - *l = nil; - - datap = listsort(datap, datcmp, listnextp); - - /* - * allocate sections. list is sorted by type, - * so we can just walk it for each piece we want to emit. - * segdata is processed before segtext, because we need - * to see all symbols in the .data and .bss sections in order - * to generate garbage collection information. - */ - - /* begin segdata */ - - /* skip symbols belonging to segtext */ - s = datap; - for(; s != nil && s->type < SELFSECT; s = s->next) - ; - - /* writable ELF sections */ - datsize = 0; - for(; s != nil && s->type < SELFGOT; s = s->next) { - sect = addsection(&segdata, s->name, 06); - sect->align = symalign(s); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - s->sect = sect; - s->type = SDATA; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - sect->length = datsize - sect->vaddr; - } - - /* .got (and .toc on ppc64) */ - if(s->type == SELFGOT) { - sect = addsection(&segdata, ".got", 06); - sect->align = maxalign(s, SELFGOT); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - for(; s != nil && s->type == SELFGOT; s = s->next) { - datsize = aligndatsize(datsize, s); - s->sect = sect; - s->type = SDATA; - s->value = datsize - sect->vaddr; - - // Resolve .TOC. symbol for this object file (ppc64) - toc = linkrlookup(ctxt, ".TOC.", s->version); - if(toc != nil) { - toc->sect = sect; - toc->outer = s; - toc->sub = s->sub; - s->sub = toc; - - toc->value = 0x8000; - } - growdatsize(&datsize, s); - } - sect->length = datsize - sect->vaddr; - } - - /* pointer-free data */ - sect = addsection(&segdata, ".noptrdata", 06); - sect->align = maxalign(s, SINITARR-1); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - linklookup(ctxt, "runtime.noptrdata", 0)->sect = sect; - linklookup(ctxt, "runtime.enoptrdata", 0)->sect = sect; - for(; s != nil && s->type < SINITARR; s = s->next) { - datsize = aligndatsize(datsize, s); - s->sect = sect; - s->type = SDATA; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - } - sect->length = datsize - sect->vaddr; - - /* shared library initializer */ - if(flag_shared) { - sect = addsection(&segdata, ".init_array", 06); - sect->align = maxalign(s, SINITARR); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - for(; s != nil && s->type == SINITARR; s = s->next) { - datsize = aligndatsize(datsize, s); - s->sect = sect; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - } - sect->length = datsize - sect->vaddr; - } - - /* data */ - sect = addsection(&segdata, ".data", 06); - sect->align = maxalign(s, SBSS-1); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - linklookup(ctxt, "runtime.data", 0)->sect = sect; - linklookup(ctxt, "runtime.edata", 0)->sect = sect; - gcdata = linklookup(ctxt, "runtime.gcdata", 0); - proggeninit(&gen, gcdata); - for(; s != nil && s->type < SBSS; s = s->next) { - if(s->type == SINITARR) { - ctxt->cursym = s; - diag("unexpected symbol type %d", s->type); - } - s->sect = sect; - s->type = SDATA; - datsize = aligndatsize(datsize, s); - s->value = datsize - sect->vaddr; - proggenaddsym(&gen, s); // gc - growdatsize(&datsize, s); - } - sect->length = datsize - sect->vaddr; - proggenfini(&gen, sect->length); // gc - - /* bss */ - sect = addsection(&segdata, ".bss", 06); - sect->align = maxalign(s, SNOPTRBSS-1); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - linklookup(ctxt, "runtime.bss", 0)->sect = sect; - linklookup(ctxt, "runtime.ebss", 0)->sect = sect; - gcbss = linklookup(ctxt, "runtime.gcbss", 0); - proggeninit(&gen, gcbss); - for(; s != nil && s->type < SNOPTRBSS; s = s->next) { - s->sect = sect; - datsize = aligndatsize(datsize, s); - s->value = datsize - sect->vaddr; - proggenaddsym(&gen, s); // gc - growdatsize(&datsize, s); - } - sect->length = datsize - sect->vaddr; - proggenfini(&gen, sect->length); // gc - - /* pointer-free bss */ - sect = addsection(&segdata, ".noptrbss", 06); - sect->align = maxalign(s, SNOPTRBSS); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - linklookup(ctxt, "runtime.noptrbss", 0)->sect = sect; - linklookup(ctxt, "runtime.enoptrbss", 0)->sect = sect; - for(; s != nil && s->type == SNOPTRBSS; s = s->next) { - datsize = aligndatsize(datsize, s); - s->sect = sect; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - } - sect->length = datsize - sect->vaddr; - linklookup(ctxt, "runtime.end", 0)->sect = sect; - - // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. - if(datsize != (uint32)datsize) { - diag("data or bss segment too large"); - } - - if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) { - sect = addsection(&segdata, ".tbss", 06); - sect->align = thearch.ptrsize; - sect->vaddr = 0; - datsize = 0; - for(; s != nil && s->type == STLSBSS; s = s->next) { - datsize = aligndatsize(datsize, s); - s->sect = sect; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - } - sect->length = datsize; - } else { - // Might be internal linking but still using cgo. - // In that case, the only possible STLSBSS symbol is runtime.tlsg. - // Give it offset 0, because it's the only thing here. - if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsg") == 0) { - s->value = 0; - s = s->next; - } - } - - if(s != nil) { - ctxt->cursym = nil; - diag("unexpected symbol type %d for %s", s->type, s->name); - } - - /* - * We finished data, begin read-only data. - * Not all systems support a separate read-only non-executable data section. - * ELF systems do. - * OS X and Plan 9 do not. - * Windows PE may, but if so we have not implemented it. - * And if we're using external linking mode, the point is moot, - * since it's not our decision; that code expects the sections in - * segtext. - */ - if(iself && linkmode == LinkInternal) - segro = &segrodata; - else - segro = &segtext; - - s = datap; - - datsize = 0; - - /* read-only executable ELF, Mach-O sections */ - for(; s != nil && s->type < STYPE; s = s->next) { - sect = addsection(&segtext, s->name, 04); - sect->align = symalign(s); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - s->sect = sect; - s->type = SRODATA; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - sect->length = datsize - sect->vaddr; - } - - /* read-only data */ - sect = addsection(segro, ".rodata", 04); - sect->align = maxalign(s, STYPELINK-1); - datsize = rnd(datsize, sect->align); - sect->vaddr = 0; - linklookup(ctxt, "runtime.rodata", 0)->sect = sect; - linklookup(ctxt, "runtime.erodata", 0)->sect = sect; - for(; s != nil && s->type < STYPELINK; s = s->next) { - datsize = aligndatsize(datsize, s); - s->sect = sect; - s->type = SRODATA; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - } - sect->length = datsize - sect->vaddr; - - /* typelink */ - sect = addsection(segro, ".typelink", 04); - sect->align = maxalign(s, STYPELINK); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - linklookup(ctxt, "runtime.typelink", 0)->sect = sect; - linklookup(ctxt, "runtime.etypelink", 0)->sect = sect; - for(; s != nil && s->type == STYPELINK; s = s->next) { - datsize = aligndatsize(datsize, s); - s->sect = sect; - s->type = SRODATA; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - } - sect->length = datsize - sect->vaddr; - - /* gosymtab */ - sect = addsection(segro, ".gosymtab", 04); - sect->align = maxalign(s, SPCLNTAB-1); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - linklookup(ctxt, "runtime.symtab", 0)->sect = sect; - linklookup(ctxt, "runtime.esymtab", 0)->sect = sect; - for(; s != nil && s->type < SPCLNTAB; s = s->next) { - datsize = aligndatsize(datsize, s); - s->sect = sect; - s->type = SRODATA; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - } - sect->length = datsize - sect->vaddr; - - /* gopclntab */ - sect = addsection(segro, ".gopclntab", 04); - sect->align = maxalign(s, SELFROSECT-1); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - linklookup(ctxt, "runtime.pclntab", 0)->sect = sect; - linklookup(ctxt, "runtime.epclntab", 0)->sect = sect; - for(; s != nil && s->type < SELFROSECT; s = s->next) { - datsize = aligndatsize(datsize, s); - s->sect = sect; - s->type = SRODATA; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - } - sect->length = datsize - sect->vaddr; - - /* read-only ELF, Mach-O sections */ - for(; s != nil && s->type < SELFSECT; s = s->next) { - sect = addsection(segro, s->name, 04); - sect->align = symalign(s); - datsize = rnd(datsize, sect->align); - sect->vaddr = datsize; - s->sect = sect; - s->type = SRODATA; - s->value = datsize - sect->vaddr; - growdatsize(&datsize, s); - sect->length = datsize - sect->vaddr; - } - - // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. - if(datsize != (uint32)datsize) { - diag("read-only data segment too large"); - } - - /* number the sections */ - n = 1; - for(sect = segtext.sect; sect != nil; sect = sect->next) - sect->extnum = n++; - for(sect = segrodata.sect; sect != nil; sect = sect->next) - sect->extnum = n++; - for(sect = segdata.sect; sect != nil; sect = sect->next) - sect->extnum = n++; -} - -// assign addresses to text -void -textaddress(void) -{ - uvlong va; - Section *sect; - LSym *sym, *sub; - - addsection(&segtext, ".text", 05); - - // Assign PCs in text segment. - // Could parallelize, by assigning to text - // and then letting threads copy down, but probably not worth it. - sect = segtext.sect; - sect->align = funcalign; - linklookup(ctxt, "runtime.text", 0)->sect = sect; - linklookup(ctxt, "runtime.etext", 0)->sect = sect; - va = INITTEXT; - sect->vaddr = va; - for(sym = ctxt->textp; sym != nil; sym = sym->next) { - sym->sect = sect; - if(sym->type & SSUB) - continue; - if(sym->align != 0) - va = rnd(va, sym->align); - else - va = rnd(va, funcalign); - sym->value = 0; - for(sub = sym; sub != nil; sub = sub->sub) - sub->value += va; - if(sym->size == 0 && sym->sub != nil) - ctxt->cursym = sym; - if(sym->size < MINFUNC) - va += MINFUNC; // spacing required for findfunctab - else - va += sym->size; - } - sect->length = va - sect->vaddr; -} - -// assign addresses -void -address(void) -{ - Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; - Section *typelink; - LSym *sym, *sub; - uvlong va; - vlong vlen; - - va = INITTEXT; - segtext.rwx = 05; - segtext.vaddr = va; - segtext.fileoff = HEADR; - for(s=segtext.sect; s != nil; s=s->next) { - va = rnd(va, s->align); - s->vaddr = va; - va += s->length; - } - segtext.length = va - INITTEXT; - segtext.filelen = segtext.length; - if(HEADTYPE == Hnacl) - va += 32; // room for the "halt sled" - - if(segrodata.sect != nil) { - // align to page boundary so as not to mix - // rodata and executable text. - va = rnd(va, INITRND); - - segrodata.rwx = 04; - segrodata.vaddr = va; - segrodata.fileoff = va - segtext.vaddr + segtext.fileoff; - segrodata.filelen = 0; - for(s=segrodata.sect; s != nil; s=s->next) { - va = rnd(va, s->align); - s->vaddr = va; - va += s->length; - } - segrodata.length = va - segrodata.vaddr; - segrodata.filelen = segrodata.length; - } - - va = rnd(va, INITRND); - segdata.rwx = 06; - segdata.vaddr = va; - segdata.fileoff = va - segtext.vaddr + segtext.fileoff; - segdata.filelen = 0; - if(HEADTYPE == Hwindows) - segdata.fileoff = segtext.fileoff + rnd(segtext.length, PEFILEALIGN); - if(HEADTYPE == Hplan9) - segdata.fileoff = segtext.fileoff + segtext.filelen; - data = nil; - noptr = nil; - bss = nil; - noptrbss = nil; - for(s=segdata.sect; s != nil; s=s->next) { - vlen = s->length; - if(s->next) - vlen = s->next->vaddr - s->vaddr; - s->vaddr = va; - va += vlen; - segdata.length = va - segdata.vaddr; - if(strcmp(s->name, ".data") == 0) - data = s; - if(strcmp(s->name, ".noptrdata") == 0) - noptr = s; - if(strcmp(s->name, ".bss") == 0) - bss = s; - if(strcmp(s->name, ".noptrbss") == 0) - noptrbss = s; - } - segdata.filelen = bss->vaddr - segdata.vaddr; - - text = segtext.sect; - if(segrodata.sect) - rodata = segrodata.sect; - else - rodata = text->next; - typelink = rodata->next; - symtab = typelink->next; - pclntab = symtab->next; - - for(sym = datap; sym != nil; sym = sym->next) { - ctxt->cursym = sym; - if(sym->sect != nil) - sym->value += ((Section*)sym->sect)->vaddr; - for(sub = sym->sub; sub != nil; sub = sub->sub) - sub->value += sym->value; - } - - xdefine("runtime.text", STEXT, text->vaddr); - xdefine("runtime.etext", STEXT, text->vaddr + text->length); - xdefine("runtime.rodata", SRODATA, rodata->vaddr); - xdefine("runtime.erodata", SRODATA, rodata->vaddr + rodata->length); - xdefine("runtime.typelink", SRODATA, typelink->vaddr); - xdefine("runtime.etypelink", SRODATA, typelink->vaddr + typelink->length); - - sym = linklookup(ctxt, "runtime.gcdata", 0); - xdefine("runtime.egcdata", SRODATA, symaddr(sym) + sym->size); - linklookup(ctxt, "runtime.egcdata", 0)->sect = sym->sect; - - sym = linklookup(ctxt, "runtime.gcbss", 0); - xdefine("runtime.egcbss", SRODATA, symaddr(sym) + sym->size); - linklookup(ctxt, "runtime.egcbss", 0)->sect = sym->sect; - - xdefine("runtime.symtab", SRODATA, symtab->vaddr); - xdefine("runtime.esymtab", SRODATA, symtab->vaddr + symtab->length); - xdefine("runtime.pclntab", SRODATA, pclntab->vaddr); - xdefine("runtime.epclntab", SRODATA, pclntab->vaddr + pclntab->length); - xdefine("runtime.noptrdata", SNOPTRDATA, noptr->vaddr); - xdefine("runtime.enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->length); - xdefine("runtime.bss", SBSS, bss->vaddr); - xdefine("runtime.ebss", SBSS, bss->vaddr + bss->length); - xdefine("runtime.data", SDATA, data->vaddr); - xdefine("runtime.edata", SDATA, data->vaddr + data->length); - xdefine("runtime.noptrbss", SNOPTRBSS, noptrbss->vaddr); - xdefine("runtime.enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->length); - xdefine("runtime.end", SBSS, segdata.vaddr + segdata.length); -} diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c deleted file mode 100644 index e320e0fff8..0000000000 --- a/src/cmd/ld/decodesym.c +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include -#include -#include "lib.h" -#include "../../runtime/typekind.h" - -// Decoding the type.* symbols. This has to be in sync with -// ../../runtime/type.go, or more specifically, with what -// ../gc/reflect.c stuffs in these. - -static Reloc* -decode_reloc(LSym *s, int32 off) -{ - int i; - - for (i = 0; i < s->nr; i++) - if (s->r[i].off == off) - return s->r + i; - return nil; -} - -static LSym* -decode_reloc_sym(LSym *s, int32 off) -{ - Reloc *r; - - r = decode_reloc(s,off); - if (r == nil) - return nil; - return r->sym; -} - -static uvlong -decode_inuxi(uchar* p, int sz) -{ - uint64 v; - uint32 l; - uchar *cast, *inuxi; - int i; - - v = l = 0; - cast = nil; - inuxi = nil; - switch (sz) { - case 2: - cast = (uchar*)&l; - inuxi = inuxi2; - break; - case 4: - cast = (uchar*)&l; - inuxi = inuxi4; - break; - case 8: - cast = (uchar*)&v; - inuxi = inuxi8; - break; - default: - diag("dwarf: decode inuxi %d", sz); - errorexit(); - } - for (i = 0; i < sz; i++) - cast[inuxi[i]] = p[i]; - if (sz == 8) - return v; - return l; -} - -static int -commonsize(void) -{ - return 8*thearch.ptrsize + 8; -} - -// Type.commonType.kind -uint8 -decodetype_kind(LSym *s) -{ - return s->p[1*thearch.ptrsize + 7] & KindMask; // 0x13 / 0x1f -} - -// Type.commonType.kind -uint8 -decodetype_noptr(LSym *s) -{ - return s->p[1*thearch.ptrsize + 7] & KindNoPointers; // 0x13 / 0x1f -} - -// Type.commonType.kind -uint8 -decodetype_usegcprog(LSym *s) -{ - return s->p[1*thearch.ptrsize + 7] & KindGCProg; // 0x13 / 0x1f -} - -// Type.commonType.size -vlong -decodetype_size(LSym *s) -{ - return decode_inuxi(s->p, thearch.ptrsize); // 0x8 / 0x10 -} - -// Type.commonType.gc -LSym* -decodetype_gcprog(LSym *s) -{ - return decode_reloc_sym(s, 1*thearch.ptrsize + 8 + 2*thearch.ptrsize); -} - -uint8* -decodetype_gcmask(LSym *s) -{ - LSym *mask; - - mask = decode_reloc_sym(s, 1*thearch.ptrsize + 8 + 1*thearch.ptrsize); - return mask->p; -} - -// Type.ArrayType.elem and Type.SliceType.Elem -LSym* -decodetype_arrayelem(LSym *s) -{ - return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 -} - -vlong -decodetype_arraylen(LSym *s) -{ - return decode_inuxi(s->p + commonsize()+2*thearch.ptrsize, thearch.ptrsize); -} - -// Type.PtrType.elem -LSym* -decodetype_ptrelem(LSym *s) -{ - return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 -} - -// Type.MapType.key, elem -LSym* -decodetype_mapkey(LSym *s) -{ - return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 -} - -LSym* -decodetype_mapvalue(LSym *s) -{ - return decode_reloc_sym(s, commonsize()+thearch.ptrsize); // 0x20 / 0x38 -} - -// Type.ChanType.elem -LSym* -decodetype_chanelem(LSym *s) -{ - return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 -} - -// Type.FuncType.dotdotdot -int -decodetype_funcdotdotdot(LSym *s) -{ - return s->p[commonsize()]; -} - -// Type.FuncType.in.length -int -decodetype_funcincount(LSym *s) -{ - return decode_inuxi(s->p + commonsize()+2*thearch.ptrsize, thearch.intsize); -} - -int -decodetype_funcoutcount(LSym *s) -{ - return decode_inuxi(s->p + commonsize()+3*thearch.ptrsize + 2*thearch.intsize, thearch.intsize); -} - -LSym* -decodetype_funcintype(LSym *s, int i) -{ - Reloc *r; - - r = decode_reloc(s, commonsize() + thearch.ptrsize); - if (r == nil) - return nil; - return decode_reloc_sym(r->sym, r->add + i * thearch.ptrsize); -} - -LSym* -decodetype_funcouttype(LSym *s, int i) -{ - Reloc *r; - - r = decode_reloc(s, commonsize() + 2*thearch.ptrsize + 2*thearch.intsize); - if (r == nil) - return nil; - return decode_reloc_sym(r->sym, r->add + i * thearch.ptrsize); -} - -// Type.StructType.fields.Slice::length -int -decodetype_structfieldcount(LSym *s) -{ - return decode_inuxi(s->p + commonsize() + thearch.ptrsize, thearch.intsize); -} - -static int -structfieldsize(void) -{ - return 5*thearch.ptrsize; -} - -// Type.StructType.fields[]-> name, typ and offset. -char* -decodetype_structfieldname(LSym *s, int i) -{ - Reloc *r; - - // go.string."foo" 0x28 / 0x40 - s = decode_reloc_sym(s, commonsize() + thearch.ptrsize + 2*thearch.intsize + i*structfieldsize()); - if (s == nil) // embedded structs have a nil name. - return nil; - r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0 - if (r == nil) // shouldn't happen. - return nil; - return (char*) r->sym->p + r->add; // the c-string -} - -LSym* -decodetype_structfieldtype(LSym *s, int i) -{ - return decode_reloc_sym(s, commonsize() + thearch.ptrsize + 2*thearch.intsize + i*structfieldsize() + 2*thearch.ptrsize); -} - -vlong -decodetype_structfieldoffs(LSym *s, int i) -{ - return decode_inuxi(s->p + commonsize() + thearch.ptrsize + 2*thearch.intsize + i*structfieldsize() + 4*thearch.ptrsize, thearch.intsize); -} - -// InterfaceTYpe.methods.length -vlong -decodetype_ifacemethodcount(LSym *s) -{ - return decode_inuxi(s->p + commonsize() + thearch.ptrsize, thearch.intsize); -} diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go deleted file mode 100644 index ad35df7400..0000000000 --- a/src/cmd/ld/doc.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -Ld is the portable code for a modified version of the Plan 9 linker. The original is documented at - - http://plan9.bell-labs.com/magic/man2html/1/8l - -It reads object files (.5, .6, .8, .9 files) and writes a binary named for the -architecture (5.out, 6.out, 8.out, 9.out) by default (if $GOOS is windows, a .exe suffix -will be appended). - -Major changes include: - - support for ELF, Mach-O and PE binary files - - support for segmented stacks (this feature is implemented here, not in the compilers). - -Original options are listed on the manual page linked above. - -Usage: - go tool 6l [flags] mainObj -Substitute 6l with 5l, 8l or 9l as appropriate. - -Options new in this version: - - -d - Elide the dynamic linking header. With this option, the binary - is statically linked and does not refer to a dynamic linker. Without this option - (the default), the binary's contents are identical but it is loaded with a dynamic - linker. This flag cannot be used when $GOOS is windows. - -H darwin (only in 6l/8l) - Write Apple Mach-O binaries (default when $GOOS is darwin) - -H dragonfly (only in 6l/8l) - Write DragonFly ELF binaries (default when $GOOS is dragonfly) - -H linux - Write Linux ELF binaries (default when $GOOS is linux) - -H freebsd - Write FreeBSD ELF binaries (default when $GOOS is freebsd) - -H netbsd - Write NetBSD ELF binaries (default when $GOOS is netbsd) - -H openbsd (only in 6l/8l) - Write OpenBSD ELF binaries (default when $GOOS is openbsd) - -H solaris (only in 6l) - Write Solaris ELF binaries (default when $GOOS is solaris) - -H windows (only in 6l/8l) - Write Windows PE32+ Console binaries (default when $GOOS is windows) - -H windowsgui (only in 6l/8l) - Write Windows PE32+ GUI binaries - -I interpreter - Set the ELF dynamic linker to use. - -L dir1 -L dir2 - Search for libraries (package files) in dir1, dir2, etc. - The default is the single location $GOROOT/pkg/$GOOS_$GOARCH. - -r dir1:dir2:... - Set the dynamic linker search path when using ELF. - -s - Omit the symbol table and debug information. - -V - Print the linker version. - -w - Omit the DWARF symbol table. - -X symbol value - Set the value of a string variable. The symbol name - should be of the form importpath.name, as displayed - in the symbol table printed by "go tool nm". - -race - Link with race detection libraries. - -B value - Add a NT_GNU_BUILD_ID note when using ELF. The value - should start with 0x and be an even number of hex digits. - -Z - Zero stack on function entry. This is expensive but it might - be useful in cases where you are suffering from false positives - during garbage collection and are willing to trade the CPU time - for getting rid of the false positives. - NOTE: it only eliminates false positives caused by other function - calls, not false positives caused by dead temporaries stored in - the current function call. - -linkmode argument - Set the linkmode. The argument must be one of - internal, external, or auto. The default is auto. - This sets the linking mode as described in - ../cgo/doc.go. - -tmpdir dir - Set the location to use for any temporary files. The - default is a newly created directory that is removed - after the linker completes. Temporary files are only - used in external linking mode. - -extld name - Set the name of the external linker to use in external - linking mode. The default is "gcc". - -extldflags flags - Set space-separated trailing flags to pass to the - external linker in external linking mode. The default - is to not pass any additional trailing flags. -*/ -package main diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c deleted file mode 100644 index d3be4097af..0000000000 --- a/src/cmd/ld/dwarf.c +++ /dev/null @@ -1,2498 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// TODO/NICETOHAVE: -// - eliminate DW_CLS_ if not used -// - package info in compilation units -// - assign global variables and types to their packages -// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg -// ptype struct '[]uint8' and qualifiers need to be quoted away -// - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean. -// - file:line info for variables -// - make strings a typedef so prettyprinters can see the underlying string type -// -#include -#include -#include -#include -#include "lib.h" -#include "dwarf.h" -#include "dwarf_defs.h" -#include "elf.h" -#include "macho.h" -#include "pe.h" -#include "../../runtime/typekind.h" - -/* - * Offsets and sizes of the debug_* sections in the cout file. - */ - -static vlong abbrevo; -static vlong abbrevsize; -static LSym* abbrevsym; -static vlong abbrevsympos; -static vlong lineo; -static vlong linesize; -static LSym* linesym; -static vlong linesympos; -static vlong infoo; // also the base for DWDie->offs and reference attributes. -static vlong infosize; -static LSym* infosym; -static vlong infosympos; -static vlong frameo; -static vlong framesize; -static LSym* framesym; -static vlong framesympos; -static vlong pubnameso; -static vlong pubnamessize; -static vlong pubtypeso; -static vlong pubtypessize; -static vlong arangeso; -static vlong arangessize; -static vlong gdbscripto; -static vlong gdbscriptsize; - -static LSym *infosec; -static vlong inforeloco; -static vlong inforelocsize; - -static LSym *arangessec; -static vlong arangesreloco; -static vlong arangesrelocsize; - -static LSym *linesec; -static vlong linereloco; -static vlong linerelocsize; - -static LSym *framesec; -static vlong framereloco; -static vlong framerelocsize; - -static char gdbscript[1024]; - -/* - * Basic I/O - */ - -static void -addrput(vlong addr) -{ - switch(thearch.ptrsize) { - case 4: - thearch.lput(addr); - break; - case 8: - thearch.vput(addr); - break; - } -} - -static int -uleb128enc(uvlong v, char* dst) -{ - uint8 c, length; - - length = 0; - do { - c = v & 0x7f; - v >>= 7; - if (v) - c |= 0x80; - if (dst) - *dst++ = c; - length++; - } while (c & 0x80); - return length; -} - -static int -sleb128enc(vlong v, char *dst) -{ - uint8 c, s, length; - - length = 0; - do { - c = v & 0x7f; - s = v & 0x40; - v >>= 7; - if ((v != -1 || !s) && (v != 0 || s)) - c |= 0x80; - if (dst) - *dst++ = c; - length++; - } while(c & 0x80); - return length; -} - -static void -uleb128put(vlong v) -{ - char buf[10]; - strnput(buf, uleb128enc(v, buf)); -} - -static void -sleb128put(vlong v) -{ - char buf[10]; - strnput(buf, sleb128enc(v, buf)); -} - -/* - * Defining Abbrevs. This is hardcoded, and there will be - * only a handful of them. The DWARF spec places no restriction on - * the ordering of attributes in the Abbrevs and DIEs, and we will - * always write them out in the order of declaration in the abbrev. - */ -typedef struct DWAttrForm DWAttrForm; -struct DWAttrForm { - uint16 attr; - uint8 form; -}; - -// Go-specific type attributes. -enum { - DW_AT_go_kind = 0x2900, - DW_AT_go_key = 0x2901, - DW_AT_go_elem = 0x2902, - - DW_AT_internal_location = 253, // params and locals; not emitted -}; - -// Index into the abbrevs table below. -// Keep in sync with ispubname() and ispubtype() below. -// ispubtype considers >= NULLTYPE public -enum -{ - DW_ABRV_NULL, - DW_ABRV_COMPUNIT, - DW_ABRV_FUNCTION, - DW_ABRV_VARIABLE, - DW_ABRV_AUTO, - DW_ABRV_PARAM, - DW_ABRV_STRUCTFIELD, - DW_ABRV_FUNCTYPEPARAM, - DW_ABRV_DOTDOTDOT, - DW_ABRV_ARRAYRANGE, - DW_ABRV_NULLTYPE, - DW_ABRV_BASETYPE, - DW_ABRV_ARRAYTYPE, - DW_ABRV_CHANTYPE, - DW_ABRV_FUNCTYPE, - DW_ABRV_IFACETYPE, - DW_ABRV_MAPTYPE, - DW_ABRV_PTRTYPE, - DW_ABRV_BARE_PTRTYPE, // only for void*, no DW_AT_type attr to please gdb 6. - DW_ABRV_SLICETYPE, - DW_ABRV_STRINGTYPE, - DW_ABRV_STRUCTTYPE, - DW_ABRV_TYPEDECL, - DW_NABRV -}; - -typedef struct DWAbbrev DWAbbrev; -static struct DWAbbrev { - uint8 tag; - uint8 children; - DWAttrForm attr[30]; -} abbrevs[DW_NABRV] = { - /* The mandatory DW_ABRV_NULL entry. */ - { 0 }, - /* COMPUNIT */ - { - DW_TAG_compile_unit, DW_CHILDREN_yes, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_language, DW_FORM_data1}, - {DW_AT_low_pc, DW_FORM_addr}, - {DW_AT_high_pc, DW_FORM_addr}, - {DW_AT_stmt_list, DW_FORM_data4}, - {0, 0}} - }, - /* FUNCTION */ - { - DW_TAG_subprogram, DW_CHILDREN_yes, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_low_pc, DW_FORM_addr}, - {DW_AT_high_pc, DW_FORM_addr}, - {DW_AT_external, DW_FORM_flag}, - {0, 0}} - }, - /* VARIABLE */ - { - DW_TAG_variable, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_location, DW_FORM_block1}, - {DW_AT_type, DW_FORM_ref_addr}, - {DW_AT_external, DW_FORM_flag}, - {0, 0}} - }, - /* AUTO */ - { - DW_TAG_variable, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_location, DW_FORM_block1}, - {DW_AT_type, DW_FORM_ref_addr}, - {0, 0}} - }, - /* PARAM */ - { - DW_TAG_formal_parameter, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_location, DW_FORM_block1}, - {DW_AT_type, DW_FORM_ref_addr}, - {0, 0}} - }, - /* STRUCTFIELD */ - { - DW_TAG_member, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_data_member_location, DW_FORM_block1}, - {DW_AT_type, DW_FORM_ref_addr}, - {0, 0}} - }, - /* FUNCTYPEPARAM */ - { - DW_TAG_formal_parameter, DW_CHILDREN_no, - // No name! - {{DW_AT_type, DW_FORM_ref_addr}, - {0, 0}} - }, - - /* DOTDOTDOT */ - { - DW_TAG_unspecified_parameters, DW_CHILDREN_no, - {{0, 0}} - }, - /* ARRAYRANGE */ - { - DW_TAG_subrange_type, DW_CHILDREN_no, - // No name! - {{DW_AT_type, DW_FORM_ref_addr}, - {DW_AT_count, DW_FORM_udata}, - {0, 0}} - }, - - // Below here are the types considered public by ispubtype - /* NULLTYPE */ - { - DW_TAG_unspecified_type, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {0, 0}} - }, - /* BASETYPE */ - { - DW_TAG_base_type, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_encoding, DW_FORM_data1}, - {DW_AT_byte_size, DW_FORM_data1}, - {DW_AT_go_kind, DW_FORM_data1}, - {0, 0}} - }, - /* ARRAYTYPE */ - // child is subrange with upper bound - { - DW_TAG_array_type, DW_CHILDREN_yes, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_type, DW_FORM_ref_addr}, - {DW_AT_byte_size, DW_FORM_udata}, - {DW_AT_go_kind, DW_FORM_data1}, - {0, 0}} - }, - - /* CHANTYPE */ - { - DW_TAG_typedef, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_type, DW_FORM_ref_addr}, - {DW_AT_go_kind, DW_FORM_data1}, - {DW_AT_go_elem, DW_FORM_ref_addr}, - {0, 0}} - }, - - /* FUNCTYPE */ - { - DW_TAG_subroutine_type, DW_CHILDREN_yes, - {{DW_AT_name, DW_FORM_string}, -// {DW_AT_type, DW_FORM_ref_addr}, - {DW_AT_go_kind, DW_FORM_data1}, - {0, 0}} - }, - - /* IFACETYPE */ - { - DW_TAG_typedef, DW_CHILDREN_yes, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_type, DW_FORM_ref_addr}, - {DW_AT_go_kind, DW_FORM_data1}, - {0, 0}} - }, - - /* MAPTYPE */ - { - DW_TAG_typedef, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_type, DW_FORM_ref_addr}, - {DW_AT_go_kind, DW_FORM_data1}, - {DW_AT_go_key, DW_FORM_ref_addr}, - {DW_AT_go_elem, DW_FORM_ref_addr}, - {0, 0}} - }, - - /* PTRTYPE */ - { - DW_TAG_pointer_type, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_type, DW_FORM_ref_addr}, - {DW_AT_go_kind, DW_FORM_data1}, - {0, 0}} - }, - /* BARE_PTRTYPE */ - { - DW_TAG_pointer_type, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {0, 0}} - }, - - /* SLICETYPE */ - { - DW_TAG_structure_type, DW_CHILDREN_yes, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_byte_size, DW_FORM_udata}, - {DW_AT_go_kind, DW_FORM_data1}, - {DW_AT_go_elem, DW_FORM_ref_addr}, - {0, 0}} - }, - - /* STRINGTYPE */ - { - DW_TAG_structure_type, DW_CHILDREN_yes, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_byte_size, DW_FORM_udata}, - {DW_AT_go_kind, DW_FORM_data1}, - {0, 0}} - }, - - /* STRUCTTYPE */ - { - DW_TAG_structure_type, DW_CHILDREN_yes, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_byte_size, DW_FORM_udata}, - {DW_AT_go_kind, DW_FORM_data1}, - {0, 0}} - }, - - /* TYPEDECL */ - { - DW_TAG_typedef, DW_CHILDREN_no, - {{DW_AT_name, DW_FORM_string}, - {DW_AT_type, DW_FORM_ref_addr}, - {0, 0}} - }, -}; - -static void -writeabbrev(void) -{ - int i, j; - DWAttrForm *f; - - abbrevo = cpos(); - for (i = 1; i < DW_NABRV; i++) { - // See section 7.5.3 - uleb128put(i); - uleb128put(abbrevs[i].tag); - cput(abbrevs[i].children); - for(j=0; jattr); - uleb128put(f->form); - if(f->attr == 0) - break; - } - } - cput(0); - abbrevsize = cpos() - abbrevo; -} - -/* - * Debugging Information Entries and their attributes. - */ - -enum -{ - HASHSIZE = 107 -}; - -static uint32 -dwarfhashstr(char* s) -{ - uint32 h; - - h = 0; - while (*s) - h = h+h+h + *s++; - return h % HASHSIZE; -} - -// For DW_CLS_string and _block, value should contain the length, and -// data the data, for _reference, value is 0 and data is a DWDie* to -// the referenced instance, for all others, value is the whole thing -// and data is null. - -typedef struct DWAttr DWAttr; -struct DWAttr { - DWAttr *link; - uint16 atr; // DW_AT_ - uint8 cls; // DW_CLS_ - vlong value; - void *data; -}; - -typedef struct DWDie DWDie; -struct DWDie { - int abbrev; - DWDie *link; - DWDie *child; - DWAttr *attr; - // offset into .debug_info section, i.e relative to - // infoo. only valid after call to putdie() - vlong offs; - DWDie **hash; // optional index of children by name, enabled by mkindex() - DWDie *hlink; // bucket chain in parent's index -}; - -/* - * Root DIEs for compilation units, types and global variables. - */ - -static DWDie dwroot; -static DWDie dwtypes; -static DWDie dwglobals; - -static DWAttr* -newattr(DWDie *die, uint16 attr, int cls, vlong value, void *data) -{ - DWAttr *a; - - a = mal(sizeof *a); - a->link = die->attr; - die->attr = a; - a->atr = attr; - a->cls = cls; - a->value = value; - a->data = data; - return a; -} - -// Each DIE (except the root ones) has at least 1 attribute: its -// name. getattr moves the desired one to the front so -// frequently searched ones are found faster. -static DWAttr* -getattr(DWDie *die, uint16 attr) -{ - DWAttr *a, *b; - - if (die->attr->atr == attr) - return die->attr; - - a = die->attr; - b = a->link; - while (b != nil) { - if (b->atr == attr) { - a->link = b->link; - b->link = die->attr; - die->attr = b; - return b; - } - a = b; - b = b->link; - } - return nil; -} - -// Every DIE has at least a DW_AT_name attribute (but it will only be -// written out if it is listed in the abbrev). If its parent is -// keeping an index, the new DIE will be inserted there. -static DWDie* -newdie(DWDie *parent, int abbrev, char *name) -{ - DWDie *die; - int h; - - die = mal(sizeof *die); - die->abbrev = abbrev; - die->link = parent->child; - parent->child = die; - - newattr(die, DW_AT_name, DW_CLS_STRING, strlen(name), name); - - if (parent->hash) { - h = dwarfhashstr(name); - die->hlink = parent->hash[h]; - parent->hash[h] = die; - } - - return die; -} - -static void -mkindex(DWDie *die) -{ - die->hash = mal(HASHSIZE * sizeof(DWDie*)); -} - -static DWDie* -walktypedef(DWDie *die) -{ - DWAttr *attr; - - // Resolve typedef if present. - if (die->abbrev == DW_ABRV_TYPEDECL) { - for (attr = die->attr; attr; attr = attr->link) { - if (attr->atr == DW_AT_type && attr->cls == DW_CLS_REFERENCE && attr->data != nil) { - return (DWDie*)attr->data; - } - } - } - return die; -} - -// Find child by AT_name using hashtable if available or linear scan -// if not. -static DWDie* -find(DWDie *die, char* name) -{ - DWDie *a, *b, *die2; - int h; - -top: - if (die->hash == nil) { - for (a = die->child; a != nil; a = a->link) - if (strcmp(name, getattr(a, DW_AT_name)->data) == 0) - return a; - goto notfound; - } - - h = dwarfhashstr(name); - a = die->hash[h]; - - if (a == nil) - goto notfound; - - - if (strcmp(name, getattr(a, DW_AT_name)->data) == 0) - return a; - - // Move found ones to head of the list. - b = a->hlink; - while (b != nil) { - if (strcmp(name, getattr(b, DW_AT_name)->data) == 0) { - a->hlink = b->hlink; - b->hlink = die->hash[h]; - die->hash[h] = b; - return b; - } - a = b; - b = b->hlink; - } - -notfound: - die2 = walktypedef(die); - if(die2 != die) { - die = die2; - goto top; - } - - return nil; -} - -static DWDie* -find_or_diag(DWDie *die, char* name) -{ - DWDie *r; - r = find(die, name); - if (r == nil) { - diag("dwarf find: %s %p has no %s", getattr(die, DW_AT_name)->data, die, name); - errorexit(); - } - return r; -} - -static void -adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend) -{ - Reloc *r; - - r = addrel(sec); - r->sym = sym; - r->xsym = sym; - r->off = cpos() - offsetbase; - r->siz = siz; - r->type = R_ADDR; - r->add = addend; - r->xadd = addend; - if(iself && thearch.thechar == '6') - addend = 0; - switch(siz) { - case 4: - thearch.lput(addend); - break; - case 8: - thearch.vput(addend); - break; - default: - diag("bad size in adddwarfrel"); - break; - } -} - -static DWAttr* -newrefattr(DWDie *die, uint16 attr, DWDie* ref) -{ - if (ref == nil) - return nil; - return newattr(die, attr, DW_CLS_REFERENCE, 0, ref); -} - -static int fwdcount; - -static void -putattr(int abbrev, int form, int cls, vlong value, void *data) -{ - vlong off; - uchar *p; - int i; - - switch(form) { - case DW_FORM_addr: // address - if(linkmode == LinkExternal) { - value -= ((LSym*)data)->value; - adddwarfrel(infosec, (LSym*)data, infoo, thearch.ptrsize, value); - break; - } - addrput(value); - break; - - case DW_FORM_block1: // block - if(cls == DW_CLS_ADDRESS) { - cput(1+thearch.ptrsize); - cput(DW_OP_addr); - if(linkmode == LinkExternal) { - value -= ((LSym*)data)->value; - adddwarfrel(infosec, (LSym*)data, infoo, thearch.ptrsize, value); - break; - } - addrput(value); - break; - } - value &= 0xff; - cput(value); - p = data; - for(i=0; i 4 GB of debug info aka "64-bit") unit, which we don't implement. - if (data == nil) { - diag("dwarf: null reference in %d", abbrev); - if(thearch.ptrsize == 8) - thearch.vput(0); // invalid dwarf, gdb will complain. - else - thearch.lput(0); // invalid dwarf, gdb will complain. - } else { - off = ((DWDie*)data)->offs; - if (off == 0) - fwdcount++; - if(linkmode == LinkExternal) { - adddwarfrel(infosec, infosym, infoo, thearch.ptrsize, off); - break; - } - addrput(off); - } - break; - - case DW_FORM_ref1: // reference within the compilation unit - case DW_FORM_ref2: // reference - case DW_FORM_ref4: // reference - case DW_FORM_ref8: // reference - case DW_FORM_ref_udata: // reference - - case DW_FORM_strp: // string - case DW_FORM_indirect: // (see Section 7.5.3) - default: - diag("dwarf: unsupported attribute form %d / class %d", form, cls); - errorexit(); - } -} - -// Note that we can (and do) add arbitrary attributes to a DIE, but -// only the ones actually listed in the Abbrev will be written out. -static void -putattrs(int abbrev, DWAttr* attr) -{ - DWAttrForm* af; - DWAttr *ap; - - for(af = abbrevs[abbrev].attr; af->attr; af++) { - for(ap=attr; ap; ap=ap->link) { - if(ap->atr == af->attr) { - putattr(abbrev, af->form, - ap->cls, - ap->value, - ap->data); - goto done; - } - } - putattr(abbrev, af->form, 0, 0, nil); - done:; - } -} - -static void putdie(DWDie* die); - -static void -putdies(DWDie* die) -{ - for(; die; die = die->link) - putdie(die); -} - -static void -putdie(DWDie* die) -{ - die->offs = cpos() - infoo; - uleb128put(die->abbrev); - putattrs(die->abbrev, die->attr); - if (abbrevs[die->abbrev].children) { - putdies(die->child); - cput(0); - } -} - -static void -reverselist(DWDie** list) -{ - DWDie *curr, *prev; - - curr = *list; - prev = nil; - while(curr != nil) { - DWDie* next = curr->link; - curr->link = prev; - prev = curr; - curr = next; - } - *list = prev; -} - -static void -reversetree(DWDie** list) -{ - DWDie *die; - - reverselist(list); - for (die = *list; die != nil; die = die->link) - if (abbrevs[die->abbrev].children) - reversetree(&die->child); -} - -static void -newmemberoffsetattr(DWDie *die, int32 offs) -{ - char block[10]; - int i; - - i = 0; - block[i++] = DW_OP_plus_uconst; - i += uleb128enc(offs, block+i); - newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, i, mal(i)); - memmove(die->attr->data, block, i); -} - -// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a -// location expression that evals to a const. -static void -newabslocexprattr(DWDie *die, vlong addr, LSym *sym) -{ - newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, sym); -} - -static DWDie* defptrto(DWDie *dwtype); // below - -// Lookup predefined types -static LSym* -lookup_or_diag(char *n) -{ - LSym *s; - - s = linkrlookup(ctxt, n, 0); - if (s == nil || s->size == 0) { - diag("dwarf: missing type: %s", n); - errorexit(); - } - return s; -} - -static void -dotypedef(DWDie *parent, char *name, DWDie *def) -{ - DWDie *die; - - // Only emit typedefs for real names. - if(strncmp(name, "map[", 4) == 0) - return; - if(strncmp(name, "struct {", 8) == 0) - return; - if(strncmp(name, "chan ", 5) == 0) - return; - if(*name == '[' || *name == '*') - return; - if(def == nil) - diag("dwarf: bad def in dotypedef"); - - // The typedef entry must be created after the def, - // so that future lookups will find the typedef instead - // of the real definition. This hooks the typedef into any - // circular definition loops, so that gdb can understand them. - die = newdie(parent, DW_ABRV_TYPEDECL, name); - newrefattr(die, DW_AT_type, def); -} - -// Define gotype, for composite ones recurse into constituents. -static DWDie* -defgotype(LSym *gotype) -{ - DWDie *die, *fld; - LSym *s; - char *name, *f; - uint8 kind; - vlong bytesize; - int i, nfields; - - if (gotype == nil) - return find_or_diag(&dwtypes, ""); - - if (strncmp("type.", gotype->name, 5) != 0) { - diag("dwarf: type name doesn't start with \".type\": %s", gotype->name); - return find_or_diag(&dwtypes, ""); - } - name = gotype->name + 5; // could also decode from Type.string - - die = find(&dwtypes, name); - if (die != nil) - return die; - - if (0 && debug['v'] > 2) - print("new type: %Y\n", gotype); - - kind = decodetype_kind(gotype); - bytesize = decodetype_size(gotype); - - switch (kind) { - case KindBool: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindInt: - case KindInt8: - case KindInt16: - case KindInt32: - case KindInt64: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindUint: - case KindUint8: - case KindUint16: - case KindUint32: - case KindUint64: - case KindUintptr: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindFloat32: - case KindFloat64: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindComplex64: - case KindComplex128: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindArray: - die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name); - dotypedef(&dwtypes, name, die); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - s = decodetype_arrayelem(gotype); - newrefattr(die, DW_AT_type, defgotype(s)); - fld = newdie(die, DW_ABRV_ARRAYRANGE, "range"); - // use actual length not upper bound; correct for 0-length arrays. - newattr(fld, DW_AT_count, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0); - newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr")); - break; - - case KindChan: - die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - s = decodetype_chanelem(gotype); - newrefattr(die, DW_AT_go_elem, defgotype(s)); - break; - - case KindFunc: - die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name); - dotypedef(&dwtypes, name, die); - newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void")); - nfields = decodetype_funcincount(gotype); - for (i = 0; i < nfields; i++) { - s = decodetype_funcintype(gotype, i); - fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5); - newrefattr(fld, DW_AT_type, defgotype(s)); - } - if (decodetype_funcdotdotdot(gotype)) - newdie(die, DW_ABRV_DOTDOTDOT, "..."); - nfields = decodetype_funcoutcount(gotype); - for (i = 0; i < nfields; i++) { - s = decodetype_funcouttype(gotype, i); - fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5); - newrefattr(fld, DW_AT_type, defptrto(defgotype(s))); - } - break; - - case KindInterface: - die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name); - dotypedef(&dwtypes, name, die); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - nfields = decodetype_ifacemethodcount(gotype); - if (nfields == 0) - s = lookup_or_diag("type.runtime.eface"); - else - s = lookup_or_diag("type.runtime.iface"); - newrefattr(die, DW_AT_type, defgotype(s)); - break; - - case KindMap: - die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name); - s = decodetype_mapkey(gotype); - newrefattr(die, DW_AT_go_key, defgotype(s)); - s = decodetype_mapvalue(gotype); - newrefattr(die, DW_AT_go_elem, defgotype(s)); - break; - - case KindPtr: - die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name); - dotypedef(&dwtypes, name, die); - s = decodetype_ptrelem(gotype); - newrefattr(die, DW_AT_type, defgotype(s)); - break; - - case KindSlice: - die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name); - dotypedef(&dwtypes, name, die); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - s = decodetype_arrayelem(gotype); - newrefattr(die, DW_AT_go_elem, defgotype(s)); - break; - - case KindString: - die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindStruct: - die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name); - dotypedef(&dwtypes, name, die); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - nfields = decodetype_structfieldcount(gotype); - for (i = 0; i < nfields; i++) { - f = decodetype_structfieldname(gotype, i); - s = decodetype_structfieldtype(gotype, i); - if (f == nil) - f = s->name + 5; // skip "type." - fld = newdie(die, DW_ABRV_STRUCTFIELD, f); - newrefattr(fld, DW_AT_type, defgotype(s)); - newmemberoffsetattr(fld, decodetype_structfieldoffs(gotype, i)); - } - break; - - case KindUnsafePointer: - die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name); - break; - - default: - diag("dwarf: definition of unknown kind %d: %s", kind, gotype->name); - die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name); - newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "")); - } - - newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, kind, 0); - - return die; -} - -// Find or construct *T given T. -static DWDie* -defptrto(DWDie *dwtype) -{ - char ptrname[1024]; - DWDie *die; - - snprint(ptrname, sizeof ptrname, "*%s", getattr(dwtype, DW_AT_name)->data); - die = find(&dwtypes, ptrname); - if (die == nil) { - die = newdie(&dwtypes, DW_ABRV_PTRTYPE, - strcpy(mal(strlen(ptrname)+1), ptrname)); - newrefattr(die, DW_AT_type, dwtype); - } - return die; -} - -// Copies src's children into dst. Copies attributes by value. -// DWAttr.data is copied as pointer only. If except is one of -// the top-level children, it will not be copied. -static void -copychildrenexcept(DWDie *dst, DWDie *src, DWDie *except) -{ - DWDie *c; - DWAttr *a; - - for (src = src->child; src != nil; src = src->link) { - if(src == except) - continue; - c = newdie(dst, src->abbrev, getattr(src, DW_AT_name)->data); - for (a = src->attr; a != nil; a = a->link) - newattr(c, a->atr, a->cls, a->value, a->data); - copychildrenexcept(c, src, nil); - } - reverselist(&dst->child); -} -static void -copychildren(DWDie *dst, DWDie *src) -{ - copychildrenexcept(dst, src, nil); -} - -// Search children (assumed to have DW_TAG_member) for the one named -// field and set its DW_AT_type to dwtype -static void -substitutetype(DWDie *structdie, char *field, DWDie* dwtype) -{ - DWDie *child; - DWAttr *a; - - child = find_or_diag(structdie, field); - if (child == nil) - return; - - a = getattr(child, DW_AT_type); - if (a != nil) - a->data = dwtype; - else - newrefattr(child, DW_AT_type, dwtype); -} - -static void -synthesizestringtypes(DWDie* die) -{ - DWDie *prototype; - - prototype = walktypedef(defgotype(lookup_or_diag("type.runtime._string"))); - if (prototype == nil) - return; - - for (; die != nil; die = die->link) { - if (die->abbrev != DW_ABRV_STRINGTYPE) - continue; - copychildren(die, prototype); - } -} - -static void -synthesizeslicetypes(DWDie *die) -{ - DWDie *prototype, *elem; - - prototype = walktypedef(defgotype(lookup_or_diag("type.runtime.slice"))); - if (prototype == nil) - return; - - for (; die != nil; die = die->link) { - if (die->abbrev != DW_ABRV_SLICETYPE) - continue; - copychildren(die, prototype); - elem = (DWDie*) getattr(die, DW_AT_go_elem)->data; - substitutetype(die, "array", defptrto(elem)); - } -} - -static char* -mkinternaltypename(char *base, char *arg1, char *arg2) -{ - char buf[1024]; - char *n; - - if (arg2 == nil) - snprint(buf, sizeof buf, "%s<%s>", base, arg1); - else - snprint(buf, sizeof buf, "%s<%s,%s>", base, arg1, arg2); - n = mal(strlen(buf) + 1); - memmove(n, buf, strlen(buf)); - return n; -} - -// synthesizemaptypes is way too closely married to runtime/hashmap.c -enum { - MaxKeySize = 128, - MaxValSize = 128, - BucketSize = 8, -}; - -static void -synthesizemaptypes(DWDie *die) -{ - - DWDie *hash, *bucket, *dwh, *dwhk, *dwhv, *dwhb, *keytype, *valtype, *fld, *t; - int indirect_key, indirect_val; - int keysize, valsize; - DWAttr *a; - - hash = walktypedef(defgotype(lookup_or_diag("type.runtime.hmap"))); - bucket = walktypedef(defgotype(lookup_or_diag("type.runtime.bmap"))); - - if (hash == nil) - return; - - for (; die != nil; die = die->link) { - if (die->abbrev != DW_ABRV_MAPTYPE) - continue; - - keytype = walktypedef((DWDie*) getattr(die, DW_AT_go_key)->data); - valtype = walktypedef((DWDie*) getattr(die, DW_AT_go_elem)->data); - - // compute size info like hashmap.c does. - a = getattr(keytype, DW_AT_byte_size); - if(a) - keysize = a->value; - else - keysize = thearch.ptrsize; - a = getattr(valtype, DW_AT_byte_size); - if(a) - valsize = a->value; - else - valsize = thearch.ptrsize; - indirect_key = 0; - indirect_val = 0; - if(keysize > MaxKeySize) { - keysize = thearch.ptrsize; - indirect_key = 1; - } - if(valsize > MaxValSize) { - valsize = thearch.ptrsize; - indirect_val = 1; - } - - // Construct type to represent an array of BucketSize keys - dwhk = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, - mkinternaltypename("[]key", - getattr(keytype, DW_AT_name)->data, nil)); - newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * keysize, 0); - t = keytype; - if(indirect_key) - t = defptrto(keytype); - newrefattr(dwhk, DW_AT_type, t); - fld = newdie(dwhk, DW_ABRV_ARRAYRANGE, "size"); - newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0); - newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr")); - - // Construct type to represent an array of BucketSize values - dwhv = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, - mkinternaltypename("[]val", - getattr(valtype, DW_AT_name)->data, nil)); - newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * valsize, 0); - t = valtype; - if(indirect_val) - t = defptrto(valtype); - newrefattr(dwhv, DW_AT_type, t); - fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size"); - newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0); - newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr")); - - // Construct bucket - dwhb = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("bucket", - getattr(keytype, DW_AT_name)->data, - getattr(valtype, DW_AT_name)->data)); - // Copy over all fields except the field "data" from the generic bucket. - // "data" will be replaced with keys/values below. - copychildrenexcept(dwhb, bucket, find(bucket, "data")); - - fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys"); - newrefattr(fld, DW_AT_type, dwhk); - newmemberoffsetattr(fld, BucketSize); - fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values"); - newrefattr(fld, DW_AT_type, dwhv); - newmemberoffsetattr(fld, BucketSize + BucketSize * keysize); - fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow"); - newrefattr(fld, DW_AT_type, defptrto(dwhb)); - newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize)); - if(thearch.regsize > thearch.ptrsize) { - fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad"); - newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr")); - newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize) + thearch.ptrsize); - } - newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize + BucketSize * keysize + BucketSize * valsize + thearch.regsize, 0); - - // Construct hash - dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("hash", - getattr(keytype, DW_AT_name)->data, - getattr(valtype, DW_AT_name)->data)); - copychildren(dwh, hash); - substitutetype(dwh, "buckets", defptrto(dwhb)); - substitutetype(dwh, "oldbuckets", defptrto(dwhb)); - newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(hash, DW_AT_byte_size)->value, nil); - - // make map type a pointer to hash - newrefattr(die, DW_AT_type, defptrto(dwh)); - } -} - -static void -synthesizechantypes(DWDie *die) -{ - DWDie *sudog, *waitq, *hchan, - *dws, *dww, *dwh, *elemtype; - DWAttr *a; - int elemsize, sudogsize; - - sudog = walktypedef(defgotype(lookup_or_diag("type.runtime.sudog"))); - waitq = walktypedef(defgotype(lookup_or_diag("type.runtime.waitq"))); - hchan = walktypedef(defgotype(lookup_or_diag("type.runtime.hchan"))); - if (sudog == nil || waitq == nil || hchan == nil) - return; - - sudogsize = getattr(sudog, DW_AT_byte_size)->value; - - for (; die != nil; die = die->link) { - if (die->abbrev != DW_ABRV_CHANTYPE) - continue; - elemtype = (DWDie*) getattr(die, DW_AT_go_elem)->data; - a = getattr(elemtype, DW_AT_byte_size); - if(a) - elemsize = a->value; - else - elemsize = thearch.ptrsize; - - // sudog - dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("sudog", - getattr(elemtype, DW_AT_name)->data, nil)); - copychildren(dws, sudog); - substitutetype(dws, "elem", elemtype); - if(elemsize > 8) - elemsize -= 8; - else - elemsize = 0; - newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, sudogsize + elemsize, nil); - - // waitq - dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil)); - copychildren(dww, waitq); - substitutetype(dww, "first", defptrto(dws)); - substitutetype(dww, "last", defptrto(dws)); - newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(waitq, DW_AT_byte_size)->value, nil); - - // hchan - dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil)); - copychildren(dwh, hchan); - substitutetype(dwh, "recvq", dww); - substitutetype(dwh, "sendq", dww); - newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(hchan, DW_AT_byte_size)->value, nil); - - newrefattr(die, DW_AT_type, defptrto(dwh)); - } -} - -// For use with pass.c::genasmsym -static void -defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype) -{ - DWDie *dv, *dt; - - USED(size); - if (strncmp(s, "go.string.", 10) == 0) - return; - - if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0 && strncmp(s, "type..", 6) != 0) { - defgotype(sym); - return; - } - - dv = nil; - - switch (t) { - default: - return; - case 'd': - case 'b': - case 'D': - case 'B': - dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s); - newabslocexprattr(dv, v, sym); - if (ver == 0) - newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0); - // fallthrough - case 'a': - case 'p': - dt = defgotype(gotype); - } - - if (dv != nil) - newrefattr(dv, DW_AT_type, dt); -} - -static void -movetomodule(DWDie *parent) -{ - DWDie *die; - - die = dwroot.child->child; - while(die->link != nil) - die = die->link; - die->link = parent->child; -} - -// If the pcln table contains runtime/runtime.go, use that to set gdbscript path. -static void -finddebugruntimepath(LSym *s) -{ - int i; - char *p; - LSym *f; - - if(gdbscript[0] != '\x00') - return; - - for(i=0; ipcln->nfile; i++) { - f = s->pcln->file[i]; - if((p = strstr(f->name, "runtime/runtime.go")) != nil) { - *p = '\x00'; - snprint(gdbscript, sizeof gdbscript, "%sruntime/runtime-gdb.py", f->name); - *p = 'r'; - break; - } - } -} - -/* - * Generate short opcodes when possible, long ones when necessary. - * See section 6.2.5 - */ - -enum { - LINE_BASE = -1, - LINE_RANGE = 4, - OPCODE_BASE = 10 -}; - -static void -putpclcdelta(vlong delta_pc, vlong delta_lc) -{ - if (LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE) { - vlong opcode = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc); - if (OPCODE_BASE <= opcode && opcode < 256) { - cput(opcode); - return; - } - } - - if (delta_pc) { - cput(DW_LNS_advance_pc); - sleb128put(delta_pc); - } - - cput(DW_LNS_advance_line); - sleb128put(delta_lc); - cput(DW_LNS_copy); -} - -static void -newcfaoffsetattr(DWDie *die, int32 offs) -{ - char block[10]; - int i; - - i = 0; - - block[i++] = DW_OP_call_frame_cfa; - if (offs != 0) { - block[i++] = DW_OP_consts; - i += sleb128enc(offs, block+i); - block[i++] = DW_OP_plus; - } - newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i)); - memmove(die->attr->data, block, i); -} - -static char* -mkvarname(char* name, int da) -{ - char buf[1024]; - char *n; - - snprint(buf, sizeof buf, "%s#%d", name, da); - n = mal(strlen(buf) + 1); - memmove(n, buf, strlen(buf)); - return n; -} - -/* - * Walk prog table, emit line program and build DIE tree. - */ - -// flush previous compilation unit. -static void -flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_length) -{ - vlong here; - - if (dwinfo != nil && pc != 0) { - newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, pcsym); - } - - if (unitstart >= 0) { - cput(0); // start extended opcode - uleb128put(1); - cput(DW_LNE_end_sequence); - - here = cpos(); - cseek(unitstart); - thearch.lput(here - unitstart - 4); // unit_length - thearch.wput(2); // dwarf version - thearch.lput(header_length); // header length starting here - cseek(here); - } -} - -static void -writelines(void) -{ - LSym *s, *epcs; - Auto *a; - vlong unitstart, headerend, offs; - vlong pc, epc; - int i, lang, da, dt, line, file; - DWDie *dwinfo, *dwfunc, *dwvar, **dws; - DWDie *varhash[HASHSIZE]; - char *n, *nn; - Pciter pcfile, pcline; - LSym **files, *f; - - if(linesec == nil) - linesec = linklookup(ctxt, ".dwarfline", 0); - linesec->nr = 0; - - unitstart = -1; - headerend = -1; - epc = 0; - epcs = nil; - lineo = cpos(); - dwinfo = nil; - - flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10); - unitstart = cpos(); - - lang = DW_LANG_Go; - - s = ctxt->textp; - - dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup("go")); - newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0); - newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0); - newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, s); - - // Write .debug_line Line Number Program Header (sec 6.2.4) - // Fields marked with (*) must be changed for 64-bit dwarf - thearch.lput(0); // unit_length (*), will be filled in by flushunit. - thearch.wput(2); // dwarf version (appendix F) - thearch.lput(0); // header_length (*), filled in by flushunit. - // cpos == unitstart + 4 + 2 + 4 - cput(1); // minimum_instruction_length - cput(1); // default_is_stmt - cput(LINE_BASE); // line_base - cput(LINE_RANGE); // line_range - cput(OPCODE_BASE); // opcode_base - cput(0); // standard_opcode_lengths[1] - cput(1); // standard_opcode_lengths[2] - cput(1); // standard_opcode_lengths[3] - cput(1); // standard_opcode_lengths[4] - cput(1); // standard_opcode_lengths[5] - cput(0); // standard_opcode_lengths[6] - cput(0); // standard_opcode_lengths[7] - cput(0); // standard_opcode_lengths[8] - cput(1); // standard_opcode_lengths[9] - cput(0); // include_directories (empty) - - files = emallocz(ctxt->nhistfile*sizeof files[0]); - for(f = ctxt->filesyms; f != nil; f = f->next) - files[f->value-1] = f; - - for(i=0; inhistfile; i++) { - strnput(files[i]->name, strlen(files[i]->name) + 4); - // 4 zeros: the string termination + 3 fields. - } - - cput(0); // terminate file_names. - headerend = cpos(); - - cput(0); // start extended opcode - uleb128put(1 + thearch.ptrsize); - cput(DW_LNE_set_address); - - pc = s->value; - line = 1; - file = 1; - if(linkmode == LinkExternal) - adddwarfrel(linesec, s, lineo, thearch.ptrsize, 0); - else - addrput(pc); - - for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) { - s = ctxt->cursym; - - dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name); - newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, s); - epc = s->value + s->size; - epcs = s; - newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, s); - if (s->version == 0) - newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0); - - if(s->pcln == nil) - continue; - - finddebugruntimepath(s); - - pciterinit(ctxt, &pcfile, &s->pcln->pcfile); - pciterinit(ctxt, &pcline, &s->pcln->pcline); - epc = pc; - while(!pcfile.done && !pcline.done) { - if(epc - s->value >= pcfile.nextpc) { - pciternext(&pcfile); - continue; - } - if(epc - s->value >= pcline.nextpc) { - pciternext(&pcline); - continue; - } - - if(file != pcfile.value) { - cput(DW_LNS_set_file); - uleb128put(pcfile.value); - file = pcfile.value; - } - putpclcdelta(s->value + pcline.pc - pc, pcline.value - line); - - pc = s->value + pcline.pc; - line = pcline.value; - if(pcfile.nextpc < pcline.nextpc) - epc = pcfile.nextpc; - else - epc = pcline.nextpc; - epc += s->value; - } - - da = 0; - dwfunc->hash = varhash; // enable indexing of children by name - memset(varhash, 0, sizeof varhash); - for(a = s->autom; a; a = a->link) { - switch (a->name) { - case A_AUTO: - dt = DW_ABRV_AUTO; - offs = a->aoffset - thearch.ptrsize; - break; - case A_PARAM: - dt = DW_ABRV_PARAM; - offs = a->aoffset; - break; - default: - continue; - } - if (strstr(a->asym->name, ".autotmp_")) - continue; - if (find(dwfunc, a->asym->name) != nil) - n = mkvarname(a->asym->name, da); - else - n = a->asym->name; - // Drop the package prefix from locals and arguments. - nn = strrchr(n, '.'); - if (nn) - n = nn + 1; - - dwvar = newdie(dwfunc, dt, n); - newcfaoffsetattr(dwvar, offs); - newrefattr(dwvar, DW_AT_type, defgotype(a->gotype)); - - // push dwvar down dwfunc->child to preserve order - newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil); - dwfunc->child = dwvar->link; // take dwvar out from the top of the list - for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link) - if (offs > getattr(*dws, DW_AT_internal_location)->value) - break; - dwvar->link = *dws; - *dws = dwvar; - - da++; - } - - dwfunc->hash = nil; - } - - flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10); - linesize = cpos() - lineo; -} - -/* - * Emit .debug_frame - */ -enum -{ - CIERESERVE = 16, - DATAALIGNMENTFACTOR = -4, // TODO -thearch.ptrsize? - FAKERETURNCOLUMN = 16 // TODO gdb6 doesn't like > 15? -}; - -static void -putpccfadelta(vlong deltapc, vlong cfa) -{ - cput(DW_CFA_def_cfa_offset_sf); - sleb128put(cfa / DATAALIGNMENTFACTOR); - - if (deltapc < 0x40) { - cput(DW_CFA_advance_loc + deltapc); - } else if (deltapc < 0x100) { - cput(DW_CFA_advance_loc1); - cput(deltapc); - } else if (deltapc < 0x10000) { - cput(DW_CFA_advance_loc2); - thearch.wput(deltapc); - } else { - cput(DW_CFA_advance_loc4); - thearch.lput(deltapc); - } -} - -static void -writeframes(void) -{ - LSym *s; - vlong fdeo, fdesize, pad; - Pciter pcsp; - uint32 nextpc; - - if(framesec == nil) - framesec = linklookup(ctxt, ".dwarfframe", 0); - framesec->nr = 0; - frameo = cpos(); - - // Emit the CIE, Section 6.4.1 - thearch.lput(CIERESERVE); // initial length, must be multiple of thearch.ptrsize - thearch.lput(0xffffffff); // cid. - cput(3); // dwarf version (appendix F) - cput(0); // augmentation "" - uleb128put(1); // code_alignment_factor - sleb128put(DATAALIGNMENTFACTOR); // guess - uleb128put(FAKERETURNCOLUMN); // return_address_register - - cput(DW_CFA_def_cfa); - uleb128put(thearch.dwarfregsp); // register SP (**ABI-dependent, defined in l.h) - uleb128put(thearch.ptrsize); // offset - - cput(DW_CFA_offset + FAKERETURNCOLUMN); // return address - uleb128put(-thearch.ptrsize / DATAALIGNMENTFACTOR); // at cfa - x*4 - - // 4 is to exclude the length field. - pad = CIERESERVE + frameo + 4 - cpos(); - if (pad < 0) { - diag("dwarf: CIERESERVE too small by %lld bytes.", -pad); - errorexit(); - } - strnput("", pad); - - for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) { - s = ctxt->cursym; - if(s->pcln == nil) - continue; - - fdeo = cpos(); - // Emit a FDE, Section 6.4.1, starting wit a placeholder. - thearch.lput(0); // length, must be multiple of thearch.ptrsize - thearch.lput(0); // Pointer to the CIE above, at offset 0 - addrput(0); // initial location - addrput(0); // address range - - for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) { - nextpc = pcsp.nextpc; - // pciterinit goes up to the end of the function, - // but DWARF expects us to stop just before the end. - if(nextpc == s->size) { - nextpc--; - if(nextpc < pcsp.pc) - continue; - } - putpccfadelta(nextpc - pcsp.pc, thearch.ptrsize + pcsp.value); - } - - fdesize = cpos() - fdeo - 4; // exclude the length field. - pad = rnd(fdesize, thearch.ptrsize) - fdesize; - strnput("", pad); - fdesize += pad; - - // Emit the FDE header for real, Section 6.4.1. - cseek(fdeo); - thearch.lput(fdesize); - if(linkmode == LinkExternal) { - adddwarfrel(framesec, framesym, frameo, 4, 0); - adddwarfrel(framesec, s, frameo, thearch.ptrsize, 0); - } - else { - thearch.lput(0); - addrput(s->value); - } - addrput(s->size); - cseek(fdeo + 4 + fdesize); - } - - cflush(); - framesize = cpos() - frameo; -} - -/* - * Walk DWarfDebugInfoEntries, and emit .debug_info - */ -enum -{ - COMPUNITHEADERSIZE = 4+2+4+1 -}; - -static void -writeinfo(void) -{ - DWDie *compunit; - vlong unitstart, here; - - fwdcount = 0; - if (infosec == nil) - infosec = linklookup(ctxt, ".dwarfinfo", 0); - infosec->nr = 0; - - if(arangessec == nil) - arangessec = linklookup(ctxt, ".dwarfaranges", 0); - arangessec->nr = 0; - - for (compunit = dwroot.child; compunit; compunit = compunit->link) { - unitstart = cpos(); - - // Write .debug_info Compilation Unit Header (sec 7.5.1) - // Fields marked with (*) must be changed for 64-bit dwarf - // This must match COMPUNITHEADERSIZE above. - thearch.lput(0); // unit_length (*), will be filled in later. - thearch.wput(2); // dwarf version (appendix F) - - // debug_abbrev_offset (*) - if(linkmode == LinkExternal) - adddwarfrel(infosec, abbrevsym, infoo, 4, 0); - else - thearch.lput(0); - - cput(thearch.ptrsize); // address_size - - putdie(compunit); - - here = cpos(); - cseek(unitstart); - thearch.lput(here - unitstart - 4); // exclude the length field. - cseek(here); - } - cflush(); -} - -/* - * Emit .debug_pubnames/_types. _info must have been written before, - * because we need die->offs and infoo/infosize; - */ -static int -ispubname(DWDie *die) -{ - DWAttr *a; - - switch(die->abbrev) { - case DW_ABRV_FUNCTION: - case DW_ABRV_VARIABLE: - a = getattr(die, DW_AT_external); - return a && a->value; - } - return 0; -} - -static int -ispubtype(DWDie *die) -{ - return die->abbrev >= DW_ABRV_NULLTYPE; -} - -static vlong -writepub(int (*ispub)(DWDie*)) -{ - DWDie *compunit, *die; - DWAttr *dwa; - vlong unitstart, unitend, sectionstart, here; - - sectionstart = cpos(); - - for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) { - unitstart = compunit->offs - COMPUNITHEADERSIZE; - if (compunit->link != nil) - unitend = compunit->link->offs - COMPUNITHEADERSIZE; - else - unitend = infoo + infosize; - - // Write .debug_pubnames/types Header (sec 6.1.1) - thearch.lput(0); // unit_length (*), will be filled in later. - thearch.wput(2); // dwarf version (appendix F) - thearch.lput(unitstart); // debug_info_offset (of the Comp unit Header) - thearch.lput(unitend - unitstart); // debug_info_length - - for (die = compunit->child; die != nil; die = die->link) { - if (!ispub(die)) continue; - thearch.lput(die->offs - unitstart); - dwa = getattr(die, DW_AT_name); - strnput(dwa->data, dwa->value + 1); - } - thearch.lput(0); - - here = cpos(); - cseek(sectionstart); - thearch.lput(here - sectionstart - 4); // exclude the length field. - cseek(here); - - } - - return sectionstart; -} - -/* - * emit .debug_aranges. _info must have been written before, - * because we need die->offs of dw_globals. - */ -static vlong -writearanges(void) -{ - DWDie *compunit; - DWAttr *b, *e; - int headersize; - vlong sectionstart; - vlong value; - - sectionstart = cpos(); - headersize = rnd(4+2+4+1+1, thearch.ptrsize); // don't count unit_length field itself - - for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) { - b = getattr(compunit, DW_AT_low_pc); - if (b == nil) - continue; - e = getattr(compunit, DW_AT_high_pc); - if (e == nil) - continue; - - // Write .debug_aranges Header + entry (sec 6.1.2) - thearch.lput(headersize + 4*thearch.ptrsize - 4); // unit_length (*) - thearch.wput(2); // dwarf version (appendix F) - - value = compunit->offs - COMPUNITHEADERSIZE; // debug_info_offset - if(linkmode == LinkExternal) - adddwarfrel(arangessec, infosym, sectionstart, 4, value); - else - thearch.lput(value); - - cput(thearch.ptrsize); // address_size - cput(0); // segment_size - strnput("", headersize - (4+2+4+1+1)); // align to thearch.ptrsize - - if(linkmode == LinkExternal) - adddwarfrel(arangessec, (LSym*)b->data, sectionstart, thearch.ptrsize, b->value-((LSym*)b->data)->value); - else - addrput(b->value); - - addrput(e->value - b->value); - addrput(0); - addrput(0); - } - cflush(); - return sectionstart; -} - -static vlong -writegdbscript(void) -{ - vlong sectionstart; - - sectionstart = cpos(); - - if (gdbscript[0]) { - cput(1); // magic 1 byte? - strnput(gdbscript, strlen(gdbscript)+1); - cflush(); - } - return sectionstart; -} - -static void -align(vlong size) -{ - if(HEADTYPE == Hwindows) // Only Windows PE need section align. - strnput("", rnd(size, PEFILEALIGN) - size); -} - -static vlong -writedwarfreloc(LSym* s) -{ - int i, ri; - vlong start; - Reloc *r; - - start = cpos(); - for(ri=0; rinr; ri++) { - r = &s->r[ri]; - if(iself) - i = thearch.elfreloc1(r, r->off); - else if(HEADTYPE == Hdarwin) - i = thearch.machoreloc1(r, r->off); - else - i = -1; - if(i < 0) - diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name); - } - return start; -} - -/* - * This is the main entry point for generating dwarf. After emitting - * the mandatory debug_abbrev section, it calls writelines() to set up - * the per-compilation unit part of the DIE tree, while simultaneously - * emitting the debug_line section. When the final tree contains - * forward references, it will write the debug_info section in 2 - * passes. - * - */ -void -dwarfemitdebugsections(void) -{ - vlong infoe; - DWDie* die; - - if(debug['w']) // disable dwarf - return; - - if(linkmode == LinkExternal && !iself) - return; - - // For diagnostic messages. - newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes"); - - mkindex(&dwroot); - mkindex(&dwtypes); - mkindex(&dwglobals); - - // Some types that must exist to define other ones. - newdie(&dwtypes, DW_ABRV_NULLTYPE, ""); - newdie(&dwtypes, DW_ABRV_NULLTYPE, "void"); - newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer"); - - die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr"); // needed for array size - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, thearch.ptrsize, 0); - newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, KindUintptr, 0); - - // Needed by the prettyprinter code for interface inspection. - defgotype(lookup_or_diag("type.runtime._type")); - defgotype(lookup_or_diag("type.runtime.interfacetype")); - defgotype(lookup_or_diag("type.runtime.itab")); - - genasmsym(defdwsymb); - - writeabbrev(); - align(abbrevsize); - writelines(); - align(linesize); - writeframes(); - align(framesize); - - synthesizestringtypes(dwtypes.child); - synthesizeslicetypes(dwtypes.child); - synthesizemaptypes(dwtypes.child); - synthesizechantypes(dwtypes.child); - - reversetree(&dwroot.child); - reversetree(&dwtypes.child); - reversetree(&dwglobals.child); - - movetomodule(&dwtypes); - movetomodule(&dwglobals); - - infoo = cpos(); - writeinfo(); - infoe = cpos(); - pubnameso = infoe; - pubtypeso = infoe; - arangeso = infoe; - gdbscripto = infoe; - - if (fwdcount > 0) { - if (debug['v']) - Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime()); - cseek(infoo); - writeinfo(); - if (fwdcount > 0) { - diag("dwarf: unresolved references after first dwarf info pass"); - errorexit(); - } - if (infoe != cpos()) { - diag("dwarf: inconsistent second dwarf info pass"); - errorexit(); - } - } - infosize = infoe - infoo; - align(infosize); - - pubnameso = writepub(ispubname); - pubnamessize = cpos() - pubnameso; - align(pubnamessize); - - pubtypeso = writepub(ispubtype); - pubtypessize = cpos() - pubtypeso; - align(pubtypessize); - - arangeso = writearanges(); - arangessize = cpos() - arangeso; - align(arangessize); - - gdbscripto = writegdbscript(); - gdbscriptsize = cpos() - gdbscripto; - align(gdbscriptsize); - - while(cpos()&7) - cput(0); - inforeloco = writedwarfreloc(infosec); - inforelocsize = cpos() - inforeloco; - align(inforelocsize); - - arangesreloco = writedwarfreloc(arangessec); - arangesrelocsize = cpos() - arangesreloco; - align(arangesrelocsize); - - linereloco = writedwarfreloc(linesec); - linerelocsize = cpos() - linereloco; - align(linerelocsize); - - framereloco = writedwarfreloc(framesec); - framerelocsize = cpos() - framereloco; - align(framerelocsize); -} - -/* - * Elf. - */ -enum -{ - ElfStrDebugAbbrev, - ElfStrDebugAranges, - ElfStrDebugFrame, - ElfStrDebugInfo, - ElfStrDebugLine, - ElfStrDebugLoc, - ElfStrDebugMacinfo, - ElfStrDebugPubNames, - ElfStrDebugPubTypes, - ElfStrDebugRanges, - ElfStrDebugStr, - ElfStrGDBScripts, - ElfStrRelDebugInfo, - ElfStrRelDebugAranges, - ElfStrRelDebugLine, - ElfStrRelDebugFrame, - NElfStrDbg -}; - -vlong elfstrdbg[NElfStrDbg]; - -void -dwarfaddshstrings(LSym *shstrtab) -{ - if(debug['w']) // disable dwarf - return; - - elfstrdbg[ElfStrDebugAbbrev] = addstring(shstrtab, ".debug_abbrev"); - elfstrdbg[ElfStrDebugAranges] = addstring(shstrtab, ".debug_aranges"); - elfstrdbg[ElfStrDebugFrame] = addstring(shstrtab, ".debug_frame"); - elfstrdbg[ElfStrDebugInfo] = addstring(shstrtab, ".debug_info"); - elfstrdbg[ElfStrDebugLine] = addstring(shstrtab, ".debug_line"); - elfstrdbg[ElfStrDebugLoc] = addstring(shstrtab, ".debug_loc"); - elfstrdbg[ElfStrDebugMacinfo] = addstring(shstrtab, ".debug_macinfo"); - elfstrdbg[ElfStrDebugPubNames] = addstring(shstrtab, ".debug_pubnames"); - elfstrdbg[ElfStrDebugPubTypes] = addstring(shstrtab, ".debug_pubtypes"); - elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges"); - elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str"); - elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts"); - if(linkmode == LinkExternal) { - if(thearch.thechar == '6' || thearch.thechar == '9') { - elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rela.debug_info"); - elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rela.debug_aranges"); - elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rela.debug_line"); - elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rela.debug_frame"); - } else { - elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rel.debug_info"); - elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rel.debug_aranges"); - elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rel.debug_line"); - elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rel.debug_frame"); - } - - infosym = linklookup(ctxt, ".debug_info", 0); - infosym->hide = 1; - - abbrevsym = linklookup(ctxt, ".debug_abbrev", 0); - abbrevsym->hide = 1; - - linesym = linklookup(ctxt, ".debug_line", 0); - linesym->hide = 1; - - framesym = linklookup(ctxt, ".debug_frame", 0); - framesym->hide = 1; - } -} - -// Add section symbols for DWARF debug info. This is called before -// dwarfaddelfheaders. -void -dwarfaddelfsectionsyms(void) -{ - if(infosym != nil) { - infosympos = cpos(); - putelfsectionsym(infosym, 0); - } - if(abbrevsym != nil) { - abbrevsympos = cpos(); - putelfsectionsym(abbrevsym, 0); - } - if(linesym != nil) { - linesympos = cpos(); - putelfsectionsym(linesym, 0); - } - if(framesym != nil) { - framesympos = cpos(); - putelfsectionsym(framesym, 0); - } -} - -static void -dwarfaddelfrelocheader(int elfstr, ElfShdr *shdata, vlong off, vlong size) -{ - ElfShdr *sh; - - sh = newElfShdr(elfstrdbg[elfstr]); - if(thearch.thechar == '6' || thearch.thechar == '9') { - sh->type = SHT_RELA; - } else { - sh->type = SHT_REL; - } - sh->entsize = thearch.ptrsize*(2+(sh->type==SHT_RELA)); - sh->link = elfshname(".symtab")->shnum; - sh->info = shdata->shnum; - sh->off = off; - sh->size = size; - sh->addralign = thearch.ptrsize; - -} - -void -dwarfaddelfheaders(void) -{ - ElfShdr *sh, *shinfo, *sharanges, *shline, *shframe; - - if(debug['w']) // disable dwarf - return; - - sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]); - sh->type = SHT_PROGBITS; - sh->off = abbrevo; - sh->size = abbrevsize; - sh->addralign = 1; - if(abbrevsympos > 0) - putelfsymshndx(abbrevsympos, sh->shnum); - - sh = newElfShdr(elfstrdbg[ElfStrDebugLine]); - sh->type = SHT_PROGBITS; - sh->off = lineo; - sh->size = linesize; - sh->addralign = 1; - if(linesympos > 0) - putelfsymshndx(linesympos, sh->shnum); - shline = sh; - - sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]); - sh->type = SHT_PROGBITS; - sh->off = frameo; - sh->size = framesize; - sh->addralign = 1; - if(framesympos > 0) - putelfsymshndx(framesympos, sh->shnum); - shframe = sh; - - sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]); - sh->type = SHT_PROGBITS; - sh->off = infoo; - sh->size = infosize; - sh->addralign = 1; - if(infosympos > 0) - putelfsymshndx(infosympos, sh->shnum); - shinfo = sh; - - if (pubnamessize > 0) { - sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]); - sh->type = SHT_PROGBITS; - sh->off = pubnameso; - sh->size = pubnamessize; - sh->addralign = 1; - } - - if (pubtypessize > 0) { - sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes]); - sh->type = SHT_PROGBITS; - sh->off = pubtypeso; - sh->size = pubtypessize; - sh->addralign = 1; - } - - sharanges = nil; - if (arangessize) { - sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]); - sh->type = SHT_PROGBITS; - sh->off = arangeso; - sh->size = arangessize; - sh->addralign = 1; - sharanges = sh; - } - - if (gdbscriptsize) { - sh = newElfShdr(elfstrdbg[ElfStrGDBScripts]); - sh->type = SHT_PROGBITS; - sh->off = gdbscripto; - sh->size = gdbscriptsize; - sh->addralign = 1; - } - - if(inforelocsize) - dwarfaddelfrelocheader(ElfStrRelDebugInfo, shinfo, inforeloco, inforelocsize); - - if(arangesrelocsize) - dwarfaddelfrelocheader(ElfStrRelDebugAranges, sharanges, arangesreloco, arangesrelocsize); - - if(linerelocsize) - dwarfaddelfrelocheader(ElfStrRelDebugLine, shline, linereloco, linerelocsize); - - if(framerelocsize) - dwarfaddelfrelocheader(ElfStrRelDebugFrame, shframe, framereloco, framerelocsize); -} - -/* - * Macho - */ -void -dwarfaddmachoheaders(void) -{ - MachoSect *msect; - MachoSeg *ms; - vlong fakestart; - int nsect; - - if(debug['w']) // disable dwarf - return; - - // Zero vsize segments won't be loaded in memory, even so they - // have to be page aligned in the file. - fakestart = abbrevo & ~0xfff; - - nsect = 4; - if (pubnamessize > 0) - nsect++; - if (pubtypessize > 0) - nsect++; - if (arangessize > 0) - nsect++; - if (gdbscriptsize > 0) - nsect++; - - ms = newMachoSeg("__DWARF", nsect); - ms->fileoffset = fakestart; - ms->filesize = abbrevo-fakestart; - ms->vaddr = ms->fileoffset + segdata.vaddr - segdata.fileoff; - - msect = newMachoSect(ms, "__debug_abbrev", "__DWARF"); - msect->off = abbrevo; - msect->size = abbrevsize; - msect->addr = msect->off + segdata.vaddr - segdata.fileoff; - ms->filesize += msect->size; - - msect = newMachoSect(ms, "__debug_line", "__DWARF"); - msect->off = lineo; - msect->size = linesize; - msect->addr = msect->off + segdata.vaddr - segdata.fileoff; - ms->filesize += msect->size; - - msect = newMachoSect(ms, "__debug_frame", "__DWARF"); - msect->off = frameo; - msect->size = framesize; - msect->addr = msect->off + segdata.vaddr - segdata.fileoff; - ms->filesize += msect->size; - - msect = newMachoSect(ms, "__debug_info", "__DWARF"); - msect->off = infoo; - msect->size = infosize; - msect->addr = msect->off + segdata.vaddr - segdata.fileoff; - ms->filesize += msect->size; - - if (pubnamessize > 0) { - msect = newMachoSect(ms, "__debug_pubnames", "__DWARF"); - msect->off = pubnameso; - msect->size = pubnamessize; - msect->addr = msect->off + segdata.vaddr - segdata.fileoff; - ms->filesize += msect->size; - } - - if (pubtypessize > 0) { - msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF"); - msect->off = pubtypeso; - msect->size = pubtypessize; - msect->addr = msect->off + segdata.vaddr - segdata.fileoff; - ms->filesize += msect->size; - } - - if (arangessize > 0) { - msect = newMachoSect(ms, "__debug_aranges", "__DWARF"); - msect->off = arangeso; - msect->size = arangessize; - msect->addr = msect->off + segdata.vaddr - segdata.fileoff; - ms->filesize += msect->size; - } - - // TODO(lvd) fix gdb/python to load MachO (16 char section name limit) - if (gdbscriptsize > 0) { - msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF"); - msect->off = gdbscripto; - msect->size = gdbscriptsize; - msect->addr = msect->off + segdata.vaddr - segdata.fileoff; - ms->filesize += msect->size; - } -} - -/* - * Windows PE - */ -void -dwarfaddpeheaders(void) -{ - if(debug['w']) // disable dwarf - return; - - newPEDWARFSection(".debug_abbrev", abbrevsize); - newPEDWARFSection(".debug_line", linesize); - newPEDWARFSection(".debug_frame", framesize); - newPEDWARFSection(".debug_info", infosize); - newPEDWARFSection(".debug_pubnames", pubnamessize); - newPEDWARFSection(".debug_pubtypes", pubtypessize); - newPEDWARFSection(".debug_aranges", arangessize); - newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize); -} diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h deleted file mode 100644 index b2218c1476..0000000000 --- a/src/cmd/ld/dwarf.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * Emit debug_abbrevs, debug_info and debug_line sections to current - * offset in cout. - */ -void dwarfemitdebugsections(void); - -/* - * Add the dwarf section names to the ELF - * s[ection]h[eader]str[ing]tab. Prerequisite for - * dwarfaddelfheaders(). - */ -void dwarfaddshstrings(LSym *shstrtab); - -/* - * Add section headers pointing to the sections emitted in - * dwarfemitdebugsections. - */ -void dwarfaddelfheaders(void); -void dwarfaddmachoheaders(void); -void dwarfaddpeheaders(void); -void dwarfaddelfsectionsyms(void); diff --git a/src/cmd/ld/dwarf_defs.h b/src/cmd/ld/dwarf_defs.h deleted file mode 100644 index 93e99ff74f..0000000000 --- a/src/cmd/ld/dwarf_defs.h +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Cut, pasted, tr-and-awk'ed from tables in -// http://dwarfstd.org/doc/Dwarf3.pdf - -// Table 18 -enum -{ - DW_TAG_array_type = 0x01, - DW_TAG_class_type = 0x02, - DW_TAG_entry_point = 0x03, - DW_TAG_enumeration_type = 0x04, - DW_TAG_formal_parameter = 0x05, - DW_TAG_imported_declaration = 0x08, - DW_TAG_label = 0x0a, - DW_TAG_lexical_block = 0x0b, - DW_TAG_member = 0x0d, - DW_TAG_pointer_type = 0x0f, - DW_TAG_reference_type = 0x10, - DW_TAG_compile_unit = 0x11, - DW_TAG_string_type = 0x12, - DW_TAG_structure_type = 0x13, - DW_TAG_subroutine_type = 0x15, - DW_TAG_typedef = 0x16, - DW_TAG_union_type = 0x17, - DW_TAG_unspecified_parameters = 0x18, - DW_TAG_variant = 0x19, - DW_TAG_common_block = 0x1a, - DW_TAG_common_inclusion = 0x1b, - DW_TAG_inheritance = 0x1c, - DW_TAG_inlined_subroutine = 0x1d, - DW_TAG_module = 0x1e, - DW_TAG_ptr_to_member_type = 0x1f, - DW_TAG_set_type = 0x20, - DW_TAG_subrange_type = 0x21, - DW_TAG_with_stmt = 0x22, - DW_TAG_access_declaration = 0x23, - DW_TAG_base_type = 0x24, - DW_TAG_catch_block = 0x25, - DW_TAG_const_type = 0x26, - DW_TAG_constant = 0x27, - DW_TAG_enumerator = 0x28, - DW_TAG_file_type = 0x29, - DW_TAG_friend = 0x2a, - DW_TAG_namelist = 0x2b, - DW_TAG_namelist_item = 0x2c, - DW_TAG_packed_type = 0x2d, - DW_TAG_subprogram = 0x2e, - DW_TAG_template_type_parameter = 0x2f, - DW_TAG_template_value_parameter = 0x30, - DW_TAG_thrown_type = 0x31, - DW_TAG_try_block = 0x32, - DW_TAG_variant_part = 0x33, - DW_TAG_variable = 0x34, - DW_TAG_volatile_type = 0x35, - // Dwarf3 - DW_TAG_dwarf_procedure = 0x36, - DW_TAG_restrict_type = 0x37, - DW_TAG_interface_type = 0x38, - DW_TAG_namespace = 0x39, - DW_TAG_imported_module = 0x3a, - DW_TAG_unspecified_type = 0x3b, - DW_TAG_partial_unit = 0x3c, - DW_TAG_imported_unit = 0x3d, - DW_TAG_condition = 0x3f, - DW_TAG_shared_type = 0x40, - // Dwarf4 - DW_TAG_type_unit = 0x41, - DW_TAG_rvalue_reference_type = 0x42, - DW_TAG_template_alias = 0x43, - - // User defined - DW_TAG_lo_user = 0x4080, - DW_TAG_hi_user = 0xffff, - -}; - -// Table 19 -enum -{ - DW_CHILDREN_no = 0x00, - DW_CHILDREN_yes = 0x01, -}; - -// Not from the spec, but logicaly belongs here -enum -{ - DW_CLS_ADDRESS = 0x01, - DW_CLS_BLOCK, - DW_CLS_CONSTANT, - DW_CLS_FLAG, - DW_CLS_PTR, // lineptr, loclistptr, macptr, rangelistptr - DW_CLS_REFERENCE, - DW_CLS_ADDRLOC, - DW_CLS_STRING -}; - -// Table 20 -enum -{ - DW_AT_sibling = 0x01, // reference - DW_AT_location = 0x02, // block, loclistptr - DW_AT_name = 0x03, // string - DW_AT_ordering = 0x09, // constant - DW_AT_byte_size = 0x0b, // block, constant, reference - DW_AT_bit_offset = 0x0c, // block, constant, reference - DW_AT_bit_size = 0x0d, // block, constant, reference - DW_AT_stmt_list = 0x10, // lineptr - DW_AT_low_pc = 0x11, // address - DW_AT_high_pc = 0x12, // address - DW_AT_language = 0x13, // constant - DW_AT_discr = 0x15, // reference - DW_AT_discr_value = 0x16, // constant - DW_AT_visibility = 0x17, // constant - DW_AT_import = 0x18, // reference - DW_AT_string_length = 0x19, // block, loclistptr - DW_AT_common_reference = 0x1a, // reference - DW_AT_comp_dir = 0x1b, // string - DW_AT_const_value = 0x1c, // block, constant, string - DW_AT_containing_type = 0x1d, // reference - DW_AT_default_value = 0x1e, // reference - DW_AT_inline = 0x20, // constant - DW_AT_is_optional = 0x21, // flag - DW_AT_lower_bound = 0x22, // block, constant, reference - DW_AT_producer = 0x25, // string - DW_AT_prototyped = 0x27, // flag - DW_AT_return_addr = 0x2a, // block, loclistptr - DW_AT_start_scope = 0x2c, // constant - DW_AT_bit_stride = 0x2e, // constant - DW_AT_upper_bound = 0x2f, // block, constant, reference - DW_AT_abstract_origin = 0x31, // reference - DW_AT_accessibility = 0x32, // constant - DW_AT_address_class = 0x33, // constant - DW_AT_artificial = 0x34, // flag - DW_AT_base_types = 0x35, // reference - DW_AT_calling_convention = 0x36, // constant - DW_AT_count = 0x37, // block, constant, reference - DW_AT_data_member_location = 0x38, // block, constant, loclistptr - DW_AT_decl_column = 0x39, // constant - DW_AT_decl_file = 0x3a, // constant - DW_AT_decl_line = 0x3b, // constant - DW_AT_declaration = 0x3c, // flag - DW_AT_discr_list = 0x3d, // block - DW_AT_encoding = 0x3e, // constant - DW_AT_external = 0x3f, // flag - DW_AT_frame_base = 0x40, // block, loclistptr - DW_AT_friend = 0x41, // reference - DW_AT_identifier_case = 0x42, // constant - DW_AT_macro_info = 0x43, // macptr - DW_AT_namelist_item = 0x44, // block - DW_AT_priority = 0x45, // reference - DW_AT_segment = 0x46, // block, loclistptr - DW_AT_specification = 0x47, // reference - DW_AT_static_link = 0x48, // block, loclistptr - DW_AT_type = 0x49, // reference - DW_AT_use_location = 0x4a, // block, loclistptr - DW_AT_variable_parameter = 0x4b, // flag - DW_AT_virtuality = 0x4c, // constant - DW_AT_vtable_elem_location = 0x4d, // block, loclistptr - // Dwarf3 - DW_AT_allocated = 0x4e, // block, constant, reference - DW_AT_associated = 0x4f, // block, constant, reference - DW_AT_data_location = 0x50, // block - DW_AT_byte_stride = 0x51, // block, constant, reference - DW_AT_entry_pc = 0x52, // address - DW_AT_use_UTF8 = 0x53, // flag - DW_AT_extension = 0x54, // reference - DW_AT_ranges = 0x55, // rangelistptr - DW_AT_trampoline = 0x56, // address, flag, reference, string - DW_AT_call_column = 0x57, // constant - DW_AT_call_file = 0x58, // constant - DW_AT_call_line = 0x59, // constant - DW_AT_description = 0x5a, // string - DW_AT_binary_scale = 0x5b, // constant - DW_AT_decimal_scale = 0x5c, // constant - DW_AT_small = 0x5d, // reference - DW_AT_decimal_sign = 0x5e, // constant - DW_AT_digit_count = 0x5f, // constant - DW_AT_picture_string = 0x60, // string - DW_AT_mutable = 0x61, // flag - DW_AT_threads_scaled = 0x62, // flag - DW_AT_explicit = 0x63, // flag - DW_AT_object_pointer = 0x64, // reference - DW_AT_endianity = 0x65, // constant - DW_AT_elemental = 0x66, // flag - DW_AT_pure = 0x67, // flag - DW_AT_recursive = 0x68, // flag - - DW_AT_lo_user = 0x2000, // --- - DW_AT_hi_user = 0x3fff, // --- - -}; - -// Table 21 -enum -{ - DW_FORM_addr = 0x01, // address - DW_FORM_block2 = 0x03, // block - DW_FORM_block4 = 0x04, // block - DW_FORM_data2 = 0x05, // constant - DW_FORM_data4 = 0x06, // constant, lineptr, loclistptr, macptr, rangelistptr - DW_FORM_data8 = 0x07, // constant, lineptr, loclistptr, macptr, rangelistptr - DW_FORM_string = 0x08, // string - DW_FORM_block = 0x09, // block - DW_FORM_block1 = 0x0a, // block - DW_FORM_data1 = 0x0b, // constant - DW_FORM_flag = 0x0c, // flag - DW_FORM_sdata = 0x0d, // constant - DW_FORM_strp = 0x0e, // string - DW_FORM_udata = 0x0f, // constant - DW_FORM_ref_addr = 0x10, // reference - DW_FORM_ref1 = 0x11, // reference - DW_FORM_ref2 = 0x12, // reference - DW_FORM_ref4 = 0x13, // reference - DW_FORM_ref8 = 0x14, // reference - DW_FORM_ref_udata = 0x15, // reference - DW_FORM_indirect = 0x16, // (see Section 7.5.3) -}; - -// Table 24 (#operands, notes) -enum -{ - DW_OP_addr = 0x03, // 1 constant address (size target specific) - DW_OP_deref = 0x06, // 0 - DW_OP_const1u = 0x08, // 1 1-byte constant - DW_OP_const1s = 0x09, // 1 1-byte constant - DW_OP_const2u = 0x0a, // 1 2-byte constant - DW_OP_const2s = 0x0b, // 1 2-byte constant - DW_OP_const4u = 0x0c, // 1 4-byte constant - DW_OP_const4s = 0x0d, // 1 4-byte constant - DW_OP_const8u = 0x0e, // 1 8-byte constant - DW_OP_const8s = 0x0f, // 1 8-byte constant - DW_OP_constu = 0x10, // 1 ULEB128 constant - DW_OP_consts = 0x11, // 1 SLEB128 constant - DW_OP_dup = 0x12, // 0 - DW_OP_drop = 0x13, // 0 - DW_OP_over = 0x14, // 0 - DW_OP_pick = 0x15, // 1 1-byte stack index - DW_OP_swap = 0x16, // 0 - DW_OP_rot = 0x17, // 0 - DW_OP_xderef = 0x18, // 0 - DW_OP_abs = 0x19, // 0 - DW_OP_and = 0x1a, // 0 - DW_OP_div = 0x1b, // 0 - DW_OP_minus = 0x1c, // 0 - DW_OP_mod = 0x1d, // 0 - DW_OP_mul = 0x1e, // 0 - DW_OP_neg = 0x1f, // 0 - DW_OP_not = 0x20, // 0 - DW_OP_or = 0x21, // 0 - DW_OP_plus = 0x22, // 0 - DW_OP_plus_uconst = 0x23, // 1 ULEB128 addend - DW_OP_shl = 0x24, // 0 - DW_OP_shr = 0x25, // 0 - DW_OP_shra = 0x26, // 0 - DW_OP_xor = 0x27, // 0 - DW_OP_skip = 0x2f, // 1 signed 2-byte constant - DW_OP_bra = 0x28, // 1 signed 2-byte constant - DW_OP_eq = 0x29, // 0 - DW_OP_ge = 0x2a, // 0 - DW_OP_gt = 0x2b, // 0 - DW_OP_le = 0x2c, // 0 - DW_OP_lt = 0x2d, // 0 - DW_OP_ne = 0x2e, // 0 - DW_OP_lit0 = 0x30, // 0 ... - DW_OP_lit31 = 0x4f, // 0 literals 0..31 = (DW_OP_lit0 + - // literal) - DW_OP_reg0 = 0x50, // 0 .. - DW_OP_reg31 = 0x6f, // 0 reg 0..31 = (DW_OP_reg0 + regnum) - DW_OP_breg0 = 0x70, // 1 ... - DW_OP_breg31 = 0x8f, // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum) - DW_OP_regx = 0x90, // 1 ULEB128 register - DW_OP_fbreg = 0x91, // 1 SLEB128 offset - DW_OP_bregx = 0x92, // 2 ULEB128 register followed by SLEB128 offset - DW_OP_piece = 0x93, // 1 ULEB128 size of piece addressed - DW_OP_deref_size = 0x94, // 1 1-byte size of data retrieved - DW_OP_xderef_size = 0x95, // 1 1-byte size of data retrieved - DW_OP_nop = 0x96, // 0 - DW_OP_push_object_address = 0x97, // 0 - DW_OP_call2 = 0x98, // 1 2-byte offset of DIE - DW_OP_call4 = 0x99, // 1 4-byte offset of DIE - DW_OP_call_ref = 0x9a, // 1 4- or 8-byte offset of DIE - DW_OP_form_tls_address = 0x9b, // 0 - DW_OP_call_frame_cfa = 0x9c, // 0 - DW_OP_bit_piece = 0x9d, // 2 - DW_OP_lo_user = 0xe0, - DW_OP_hi_user = 0xff, -}; - -// Table 25 -enum -{ - DW_ATE_address = 0x01, - DW_ATE_boolean = 0x02, - DW_ATE_complex_float = 0x03, - DW_ATE_float = 0x04, - DW_ATE_signed = 0x05, - DW_ATE_signed_char = 0x06, - DW_ATE_unsigned = 0x07, - DW_ATE_unsigned_char = 0x08, - DW_ATE_imaginary_float = 0x09, - DW_ATE_packed_decimal = 0x0a, - DW_ATE_numeric_string = 0x0b, - DW_ATE_edited = 0x0c, - DW_ATE_signed_fixed = 0x0d, - DW_ATE_unsigned_fixed = 0x0e, - DW_ATE_decimal_float = 0x0f, - DW_ATE_lo_user = 0x80, - DW_ATE_hi_user = 0xff, -}; - -// Table 26 -enum -{ - DW_DS_unsigned = 0x01, - DW_DS_leading_overpunch = 0x02, - DW_DS_trailing_overpunch = 0x03, - DW_DS_leading_separate = 0x04, - DW_DS_trailing_separate = 0x05, -}; - -// Table 27 -enum -{ - DW_END_default = 0x00, - DW_END_big = 0x01, - DW_END_little = 0x02, - DW_END_lo_user = 0x40, - DW_END_hi_user = 0xff, -}; - -// Table 28 -enum -{ - DW_ACCESS_public = 0x01, - DW_ACCESS_protected = 0x02, - DW_ACCESS_private = 0x03, -}; - -// Table 29 -enum -{ - DW_VIS_local = 0x01, - DW_VIS_exported = 0x02, - DW_VIS_qualified = 0x03, -}; - -// Table 30 -enum -{ - DW_VIRTUALITY_none = 0x00, - DW_VIRTUALITY_virtual = 0x01, - DW_VIRTUALITY_pure_virtual = 0x02, -}; - -// Table 31 -enum -{ - DW_LANG_C89 = 0x0001, - DW_LANG_C = 0x0002, - DW_LANG_Ada83 = 0x0003, - DW_LANG_C_plus_plus = 0x0004, - DW_LANG_Cobol74 = 0x0005, - DW_LANG_Cobol85 = 0x0006, - DW_LANG_Fortran77 = 0x0007, - DW_LANG_Fortran90 = 0x0008, - DW_LANG_Pascal83 = 0x0009, - DW_LANG_Modula2 = 0x000a, - // Dwarf3 - DW_LANG_Java = 0x000b, - DW_LANG_C99 = 0x000c, - DW_LANG_Ada95 = 0x000d, - DW_LANG_Fortran95 = 0x000e, - DW_LANG_PLI = 0x000f, - DW_LANG_ObjC = 0x0010, - DW_LANG_ObjC_plus_plus = 0x0011, - DW_LANG_UPC = 0x0012, - DW_LANG_D = 0x0013, - // Dwarf4 - DW_LANG_Python = 0x0014, - // Dwarf5 - DW_LANG_Go = 0x0016, - - DW_LANG_lo_user = 0x8000, - DW_LANG_hi_user = 0xffff, -}; - -// Table 32 -enum -{ - DW_ID_case_sensitive = 0x00, - DW_ID_up_case = 0x01, - DW_ID_down_case = 0x02, - DW_ID_case_insensitive = 0x03, -}; - -// Table 33 -enum -{ - DW_CC_normal = 0x01, - DW_CC_program = 0x02, - DW_CC_nocall = 0x03, - DW_CC_lo_user = 0x40, - DW_CC_hi_user = 0xff, -}; - -// Table 34 -enum -{ - DW_INL_not_inlined = 0x00, - DW_INL_inlined = 0x01, - DW_INL_declared_not_inlined = 0x02, - DW_INL_declared_inlined = 0x03, -}; - -// Table 35 -enum -{ - DW_ORD_row_major = 0x00, - DW_ORD_col_major = 0x01, -}; - -// Table 36 -enum -{ - DW_DSC_label = 0x00, - DW_DSC_range = 0x01, -}; - -// Table 37 -enum -{ - DW_LNS_copy = 0x01, - DW_LNS_advance_pc = 0x02, - DW_LNS_advance_line = 0x03, - DW_LNS_set_file = 0x04, - DW_LNS_set_column = 0x05, - DW_LNS_negate_stmt = 0x06, - DW_LNS_set_basic_block = 0x07, - DW_LNS_const_add_pc = 0x08, - DW_LNS_fixed_advance_pc = 0x09, - // Dwarf3 - DW_LNS_set_prologue_end = 0x0a, - DW_LNS_set_epilogue_begin = 0x0b, - DW_LNS_set_isa = 0x0c, -}; - -// Table 38 -enum -{ - DW_LNE_end_sequence = 0x01, - DW_LNE_set_address = 0x02, - DW_LNE_define_file = 0x03, - DW_LNE_lo_user = 0x80, - DW_LNE_hi_user = 0xff, -}; - -// Table 39 -enum -{ - DW_MACINFO_define = 0x01, - DW_MACINFO_undef = 0x02, - DW_MACINFO_start_file = 0x03, - DW_MACINFO_end_file = 0x04, - DW_MACINFO_vendor_ext = 0xff, -}; - -// Table 40. -enum -{ // operand,... - DW_CFA_nop = 0x00, - DW_CFA_set_loc = 0x01, // address - DW_CFA_advance_loc1 = 0x02, // 1-byte delta - DW_CFA_advance_loc2 = 0x03, // 2-byte delta - DW_CFA_advance_loc4 = 0x04, // 4-byte delta - DW_CFA_offset_extended = 0x05, // ULEB128 register, ULEB128 offset - DW_CFA_restore_extended = 0x06, // ULEB128 register - DW_CFA_undefined = 0x07, // ULEB128 register - DW_CFA_same_value = 0x08, // ULEB128 register - DW_CFA_register = 0x09, // ULEB128 register, ULEB128 register - DW_CFA_remember_state = 0x0a, - DW_CFA_restore_state = 0x0b, - DW_CFA_def_cfa = 0x0c, // ULEB128 register, ULEB128 offset - DW_CFA_def_cfa_register = 0x0d, // ULEB128 register - DW_CFA_def_cfa_offset = 0x0e, // ULEB128 offset - DW_CFA_def_cfa_expression = 0x0f, // BLOCK - DW_CFA_expression = 0x10, // ULEB128 register, BLOCK - DW_CFA_offset_extended_sf = 0x11, // ULEB128 register, SLEB128 offset - DW_CFA_def_cfa_sf = 0x12, // ULEB128 register, SLEB128 offset - DW_CFA_def_cfa_offset_sf = 0x13, // SLEB128 offset - DW_CFA_val_offset = 0x14, // ULEB128, ULEB128 - DW_CFA_val_offset_sf = 0x15, // ULEB128, SLEB128 - DW_CFA_val_expression = 0x16, // ULEB128, BLOCK - - DW_CFA_lo_user = 0x1c, - DW_CFA_hi_user = 0x3f, - - // Opcodes that take an addend operand. - DW_CFA_advance_loc = 0x1<<6, // +delta - DW_CFA_offset = 0x2<<6, // +register (ULEB128 offset) - DW_CFA_restore = 0x3<<6, // +register -}; diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c deleted file mode 100644 index cd7667be37..0000000000 --- a/src/cmd/ld/elf.c +++ /dev/null @@ -1,1685 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include -#include -#include "lib.h" -#include "elf.h" -#include "dwarf.h" - -/* - * We use the 64-bit data structures on both 32- and 64-bit machines - * in order to write the code just once. The 64-bit data structure is - * written in the 32-bit format on the 32-bit machines. - */ -enum { - NSECT = 48, -}; - -int iself; - -int nelfsym = 1; - -static int elf64; -static ElfEhdr ehdr; -static ElfPhdr *phdr[NSECT]; -static ElfShdr *shdr[NSECT]; -static char *interp; - -typedef struct Elfstring Elfstring; -struct Elfstring -{ - char *s; - int off; -}; - -static Elfstring elfstr[100]; -static int nelfstr; - -static uchar buildinfo[32]; - -/* - Initialize the global variable that describes the ELF header. It will be updated as - we write section and prog headers. - */ -void -elfinit(void) -{ - iself = 1; - - switch(thearch.thechar) { - // 64-bit architectures - case '9': - if(ctxt->arch->endian == BigEndian) - ehdr.flags = 1; /* Version 1 ABI */ - else - ehdr.flags = 2; /* Version 2 ABI */ - // fallthrough - case '6': - elf64 = 1; - ehdr.phoff = ELF64HDRSIZE; /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */ - ehdr.shoff = ELF64HDRSIZE; /* Will move as we add PHeaders */ - ehdr.ehsize = ELF64HDRSIZE; /* Must be ELF64HDRSIZE */ - ehdr.phentsize = ELF64PHDRSIZE; /* Must be ELF64PHDRSIZE */ - ehdr.shentsize = ELF64SHDRSIZE; /* Must be ELF64SHDRSIZE */ - break; - - // 32-bit architectures - case '5': - // we use EABI on both linux/arm and freebsd/arm. - if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd) - ehdr.flags = 0x5000002; // has entry point, Version5 EABI - // fallthrough - default: - ehdr.phoff = ELF32HDRSIZE; /* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */ - ehdr.shoff = ELF32HDRSIZE; /* Will move as we add PHeaders */ - ehdr.ehsize = ELF32HDRSIZE; /* Must be ELF32HDRSIZE */ - ehdr.phentsize = ELF32PHDRSIZE; /* Must be ELF32PHDRSIZE */ - ehdr.shentsize = ELF32SHDRSIZE; /* Must be ELF32SHDRSIZE */ - } -} - -void -elf64phdr(ElfPhdr *e) -{ - thearch.lput(e->type); - thearch.lput(e->flags); - thearch.vput(e->off); - thearch.vput(e->vaddr); - thearch.vput(e->paddr); - thearch.vput(e->filesz); - thearch.vput(e->memsz); - thearch.vput(e->align); -} - -void -elf32phdr(ElfPhdr *e) -{ - int frag; - - if(e->type == PT_LOAD) { - // Correct ELF loaders will do this implicitly, - // but buggy ELF loaders like the one in some - // versions of QEMU won't. - frag = e->vaddr&(e->align-1); - e->off -= frag; - e->vaddr -= frag; - e->paddr -= frag; - e->filesz += frag; - e->memsz += frag; - } - thearch.lput(e->type); - thearch.lput(e->off); - thearch.lput(e->vaddr); - thearch.lput(e->paddr); - thearch.lput(e->filesz); - thearch.lput(e->memsz); - thearch.lput(e->flags); - thearch.lput(e->align); -} - -void -elf64shdr(ElfShdr *e) -{ - thearch.lput(e->name); - thearch.lput(e->type); - thearch.vput(e->flags); - thearch.vput(e->addr); - thearch.vput(e->off); - thearch.vput(e->size); - thearch.lput(e->link); - thearch.lput(e->info); - thearch.vput(e->addralign); - thearch.vput(e->entsize); -} - -void -elf32shdr(ElfShdr *e) -{ - thearch.lput(e->name); - thearch.lput(e->type); - thearch.lput(e->flags); - thearch.lput(e->addr); - thearch.lput(e->off); - thearch.lput(e->size); - thearch.lput(e->link); - thearch.lput(e->info); - thearch.lput(e->addralign); - thearch.lput(e->entsize); -} - -uint32 -elfwriteshdrs(void) -{ - int i; - - if (elf64) { - for (i = 0; i < ehdr.shnum; i++) - elf64shdr(shdr[i]); - return ehdr.shnum * ELF64SHDRSIZE; - } - for (i = 0; i < ehdr.shnum; i++) - elf32shdr(shdr[i]); - return ehdr.shnum * ELF32SHDRSIZE; -} - -void -elfsetstring(char *s, int off) -{ - if(nelfstr >= nelem(elfstr)) { - diag("too many elf strings"); - errorexit(); - } - elfstr[nelfstr].s = s; - elfstr[nelfstr].off = off; - nelfstr++; -} - -uint32 -elfwritephdrs(void) -{ - int i; - - if (elf64) { - for (i = 0; i < ehdr.phnum; i++) - elf64phdr(phdr[i]); - return ehdr.phnum * ELF64PHDRSIZE; - } - for (i = 0; i < ehdr.phnum; i++) - elf32phdr(phdr[i]); - return ehdr.phnum * ELF32PHDRSIZE; -} - -ElfPhdr* -newElfPhdr(void) -{ - ElfPhdr *e; - - e = mal(sizeof *e); - if (ehdr.phnum >= NSECT) - diag("too many phdrs"); - else - phdr[ehdr.phnum++] = e; - if (elf64) - ehdr.shoff += ELF64PHDRSIZE; - else - ehdr.shoff += ELF32PHDRSIZE; - return e; -} - -ElfShdr* -newElfShdr(vlong name) -{ - ElfShdr *e; - - e = mal(sizeof *e); - e->name = name; - e->shnum = ehdr.shnum; - if (ehdr.shnum >= NSECT) { - diag("too many shdrs"); - } else { - shdr[ehdr.shnum++] = e; - } - return e; -} - -ElfEhdr* -getElfEhdr(void) -{ - return &ehdr; -} - -uint32 -elf64writehdr(void) -{ - int i; - - for (i = 0; i < EI_NIDENT; i++) - cput(ehdr.ident[i]); - thearch.wput(ehdr.type); - thearch.wput(ehdr.machine); - thearch.lput(ehdr.version); - thearch.vput(ehdr.entry); - thearch.vput(ehdr.phoff); - thearch.vput(ehdr.shoff); - thearch.lput(ehdr.flags); - thearch.wput(ehdr.ehsize); - thearch.wput(ehdr.phentsize); - thearch.wput(ehdr.phnum); - thearch.wput(ehdr.shentsize); - thearch.wput(ehdr.shnum); - thearch.wput(ehdr.shstrndx); - return ELF64HDRSIZE; -} - -uint32 -elf32writehdr(void) -{ - int i; - - for (i = 0; i < EI_NIDENT; i++) - cput(ehdr.ident[i]); - thearch.wput(ehdr.type); - thearch.wput(ehdr.machine); - thearch.lput(ehdr.version); - thearch.lput(ehdr.entry); - thearch.lput(ehdr.phoff); - thearch.lput(ehdr.shoff); - thearch.lput(ehdr.flags); - thearch.wput(ehdr.ehsize); - thearch.wput(ehdr.phentsize); - thearch.wput(ehdr.phnum); - thearch.wput(ehdr.shentsize); - thearch.wput(ehdr.shnum); - thearch.wput(ehdr.shstrndx); - return ELF32HDRSIZE; -} - -uint32 -elfwritehdr(void) -{ - if(elf64) - return elf64writehdr(); - return elf32writehdr(); -} - -/* Taken directly from the definition document for ELF64 */ -uint32 -elfhash(uchar *name) -{ - uint32 h = 0, g; - while (*name) { - h = (h << 4) + *name++; - if (g = h & 0xf0000000) - h ^= g >> 24; - h &= 0x0fffffff; - } - return h; -} - -void -elfwritedynent(LSym *s, int tag, uint64 val) -{ - if(elf64) { - adduint64(ctxt, s, tag); - adduint64(ctxt, s, val); - } else { - adduint32(ctxt, s, tag); - adduint32(ctxt, s, val); - } -} - -void -elfwritedynentsym(LSym *s, int tag, LSym *t) -{ - elfwritedynentsymplus(s, tag, t, 0); -} - -void -elfwritedynentsymplus(LSym *s, int tag, LSym *t, vlong add) -{ - if(elf64) - adduint64(ctxt, s, tag); - else - adduint32(ctxt, s, tag); - addaddrplus(ctxt, s, t, add); -} - -void -elfwritedynentsymsize(LSym *s, int tag, LSym *t) -{ - if(elf64) - adduint64(ctxt, s, tag); - else - adduint32(ctxt, s, tag); - addsize(ctxt, s, t); -} - -int -elfinterp(ElfShdr *sh, uint64 startva, uint64 resoff, char *p) -{ - int n; - - interp = p; - n = strlen(interp)+1; - sh->addr = startva + resoff - n; - sh->off = resoff - n; - sh->size = n; - - return n; -} - -int -elfwriteinterp(void) -{ - ElfShdr *sh; - - sh = elfshname(".interp"); - cseek(sh->off); - cwrite(interp, sh->size); - return sh->size; -} - -int -elfnote(ElfShdr *sh, uint64 startva, uint64 resoff, int sz) -{ - uint64 n; - - n = sizeof(Elf_Note) + sz + resoff % 4; - - sh->type = SHT_NOTE; - sh->flags = SHF_ALLOC; - sh->addralign = 4; - sh->addr = startva + resoff - n; - sh->off = resoff - n; - sh->size = n - resoff % 4; - - return n; -} - -ElfShdr * -elfwritenotehdr(char *str, uint32 namesz, uint32 descsz, uint32 tag) -{ - ElfShdr *sh; - - sh = elfshname(str); - - // Write Elf_Note header. - cseek(sh->off); - thearch.lput(namesz); - thearch.lput(descsz); - thearch.lput(tag); - - return sh; -} - -// NetBSD Signature (as per sys/exec_elf.h) -enum { - ELF_NOTE_NETBSD_NAMESZ = 7, - ELF_NOTE_NETBSD_DESCSZ = 4, - ELF_NOTE_NETBSD_TAG = 1, - ELF_NOTE_NETBSD_VERSION = 599000000, /* NetBSD 5.99 */ -}; - -char ELF_NOTE_NETBSD_NAME[] = "NetBSD\x00\x00"; - -int -elfnetbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff) -{ - int n; - - n = rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + rnd(ELF_NOTE_NETBSD_DESCSZ, 4); - return elfnote(sh, startva, resoff, n); -} - -int -elfwritenetbsdsig(void) -{ - ElfShdr *sh; - - // Write Elf_Note header. - sh = elfwritenotehdr(".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG); - if(sh == nil) - return 0; - - // Followed by NetBSD string and version. - cwrite(ELF_NOTE_NETBSD_NAME, ELF_NOTE_NETBSD_NAMESZ + 1); - thearch.lput(ELF_NOTE_NETBSD_VERSION); - - return sh->size; -} - -// OpenBSD Signature -enum { - ELF_NOTE_OPENBSD_NAMESZ = 8, - ELF_NOTE_OPENBSD_DESCSZ = 4, - ELF_NOTE_OPENBSD_TAG = 1, - ELF_NOTE_OPENBSD_VERSION = 0, -}; -char ELF_NOTE_OPENBSD_NAME[] = "OpenBSD\x00"; - -int -elfopenbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff) -{ - int n; - - n = ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ; - return elfnote(sh, startva, resoff, n); -} - -int -elfwriteopenbsdsig(void) -{ - ElfShdr *sh; - - // Write Elf_Note header. - sh = elfwritenotehdr(".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG); - if(sh == nil) - return 0; - - // Followed by OpenBSD string and version. - cwrite(ELF_NOTE_OPENBSD_NAME, ELF_NOTE_OPENBSD_NAMESZ); - thearch.lput(ELF_NOTE_OPENBSD_VERSION); - - return sh->size; -} - -void -addbuildinfo(char *val) -{ - char *ov; - int i, b, j; - - if(val[0] != '0' || val[1] != 'x') { - fprint(2, "%s: -B argument must start with 0x: %s\n", argv0, val); - exits("usage"); - } - ov = val; - val += 2; - i = 0; - while(*val != '\x00') { - if(val[1] == '\x00') { - fprint(2, "%s: -B argument must have even number of digits: %s\n", argv0, ov); - exits("usage"); - } - b = 0; - for(j = 0; j < 2; j++, val++) { - b *= 16; - if(*val >= '0' && *val <= '9') - b += *val - '0'; - else if(*val >= 'a' && *val <= 'f') - b += *val - 'a' + 10; - else if(*val >= 'A' && *val <= 'F') - b += *val - 'A' + 10; - else { - fprint(2, "%s: -B argument contains invalid hex digit %c: %s\n", argv0, *val, ov); - exits("usage"); - } - } - if(i >= nelem(buildinfo)) { - fprint(2, "%s: -B option too long (max %d digits): %s\n", argv0, (int)nelem(buildinfo), ov); - exits("usage"); - } - buildinfo[i++] = b; - } - buildinfolen = i; -} - -// Build info note -enum { - ELF_NOTE_BUILDINFO_NAMESZ = 4, - ELF_NOTE_BUILDINFO_TAG = 3, -}; - -char ELF_NOTE_BUILDINFO_NAME[] = "GNU\x00"; - -int -elfbuildinfo(ElfShdr *sh, uint64 startva, uint64 resoff) -{ - int n; - - n = ELF_NOTE_BUILDINFO_NAMESZ + rnd(buildinfolen, 4); - return elfnote(sh, startva, resoff, n); -} - -int -elfwritebuildinfo(void) -{ - ElfShdr *sh; - - sh = elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, buildinfolen, ELF_NOTE_BUILDINFO_TAG); - if(sh == nil) - return 0; - - cwrite(ELF_NOTE_BUILDINFO_NAME, ELF_NOTE_BUILDINFO_NAMESZ); - cwrite(buildinfo, buildinfolen); - cwrite("\x00\x00\x00", rnd(buildinfolen, 4) - buildinfolen); - - return sh->size; -} - -int elfverneed; - -typedef struct Elfaux Elfaux; -typedef struct Elflib Elflib; - -struct Elflib -{ - Elflib *next; - Elfaux *aux; - char *file; -}; - -struct Elfaux -{ - Elfaux *next; - int num; - char *vers; -}; - -Elfaux* -addelflib(Elflib **list, char *file, char *vers) -{ - Elflib *lib; - Elfaux *aux; - - for(lib=*list; lib; lib=lib->next) - if(strcmp(lib->file, file) == 0) - goto havelib; - lib = mal(sizeof *lib); - lib->next = *list; - lib->file = file; - *list = lib; -havelib: - for(aux=lib->aux; aux; aux=aux->next) - if(strcmp(aux->vers, vers) == 0) - goto haveaux; - aux = mal(sizeof *aux); - aux->next = lib->aux; - aux->vers = vers; - lib->aux = aux; -haveaux: - return aux; -} - -void -elfdynhash(void) -{ - LSym *s, *sy, *dynstr; - int i, j, nbucket, b, nfile; - uint32 hc, *chain, *buckets; - int nsym; - char *name; - Elfaux **need; - Elflib *needlib; - Elflib *l; - Elfaux *x; - - if(!iself) - return; - - nsym = nelfsym; - s = linklookup(ctxt, ".hash", 0); - s->type = SELFROSECT; - s->reachable = 1; - - i = nsym; - nbucket = 1; - while(i > 0) { - ++nbucket; - i >>= 1; - } - - needlib = nil; - need = malloc(nsym * sizeof need[0]); - chain = malloc(nsym * sizeof chain[0]); - buckets = malloc(nbucket * sizeof buckets[0]); - if(need == nil || chain == nil || buckets == nil) { - ctxt->cursym = nil; - diag("out of memory"); - errorexit(); - } - memset(need, 0, nsym * sizeof need[0]); - memset(chain, 0, nsym * sizeof chain[0]); - memset(buckets, 0, nbucket * sizeof buckets[0]); - for(sy=ctxt->allsym; sy!=nil; sy=sy->allsym) { - if (sy->dynid <= 0) - continue; - - if(sy->dynimpvers) - need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers); - - name = sy->extname; - hc = elfhash((uchar*)name); - - b = hc % nbucket; - chain[sy->dynid] = buckets[b]; - buckets[b] = sy->dynid; - } - - adduint32(ctxt, s, nbucket); - adduint32(ctxt, s, nsym); - for(i = 0; inext) { - nfile++; - // header - adduint16(ctxt, s, 1); // table version - j = 0; - for(x=l->aux; x; x=x->next) - j++; - adduint16(ctxt, s, j); // aux count - adduint32(ctxt, s, addstring(dynstr, l->file)); // file string offset - adduint32(ctxt, s, 16); // offset from header to first aux - if(l->next) - adduint32(ctxt, s, 16+j*16); // offset from this header to next - else - adduint32(ctxt, s, 0); - - for(x=l->aux; x; x=x->next) { - x->num = i++; - // aux struct - adduint32(ctxt, s, elfhash((uchar*)x->vers)); // hash - adduint16(ctxt, s, 0); // flags - adduint16(ctxt, s, x->num); // other - index we refer to this by - adduint32(ctxt, s, addstring(dynstr, x->vers)); // version string offset - if(x->next) - adduint32(ctxt, s, 16); // offset from this aux to next - else - adduint32(ctxt, s, 0); - } - } - - // version references - s = linklookup(ctxt, ".gnu.version", 0); - for(i=0; inum); - } - - free(need); - - s = linklookup(ctxt, ".dynamic", 0); - elfverneed = nfile; - if(elfverneed) { - elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0)); - elfwritedynent(s, DT_VERNEEDNUM, nfile); - elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0)); - } - - if(thearch.thechar == '6' || thearch.thechar == '9') { - sy = linklookup(ctxt, ".rela.plt", 0); - if(sy->size > 0) { - elfwritedynent(s, DT_PLTREL, DT_RELA); - elfwritedynentsymsize(s, DT_PLTRELSZ, sy); - elfwritedynentsym(s, DT_JMPREL, sy); - } - } else { - sy = linklookup(ctxt, ".rel.plt", 0); - if(sy->size > 0) { - elfwritedynent(s, DT_PLTREL, DT_REL); - elfwritedynentsymsize(s, DT_PLTRELSZ, sy); - elfwritedynentsym(s, DT_JMPREL, sy); - } - } - - elfwritedynent(s, DT_NULL, 0); -} - -ElfPhdr* -elfphload(Segment *seg) -{ - ElfPhdr *ph; - - ph = newElfPhdr(); - ph->type = PT_LOAD; - if(seg->rwx & 4) - ph->flags |= PF_R; - if(seg->rwx & 2) - ph->flags |= PF_W; - if(seg->rwx & 1) - ph->flags |= PF_X; - ph->vaddr = seg->vaddr; - ph->paddr = seg->vaddr; - ph->memsz = seg->length; - ph->off = seg->fileoff; - ph->filesz = seg->filelen; - ph->align = INITRND; - - return ph; -} - -ElfShdr* -elfshname(char *name) -{ - int i, off; - ElfShdr *sh; - - for(i=0; iname == off) - return sh; - } - - sh = newElfShdr(off); - return sh; -} - -ElfShdr* -elfshalloc(Section *sect) -{ - ElfShdr *sh; - - sh = elfshname(sect->name); - sect->elfsect = sh; - return sh; -} - -ElfShdr* -elfshbits(Section *sect) -{ - ElfShdr *sh; - - sh = elfshalloc(sect); - if(sh->type > 0) - return sh; - - if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) - sh->type = SHT_PROGBITS; - else - sh->type = SHT_NOBITS; - sh->flags = SHF_ALLOC; - if(sect->rwx & 1) - sh->flags |= SHF_EXECINSTR; - if(sect->rwx & 2) - sh->flags |= SHF_WRITE; - if(strcmp(sect->name, ".tbss") == 0) { - if(strcmp(goos, "android") != 0) - sh->flags |= SHF_TLS; // no TLS on android - sh->type = SHT_NOBITS; - } - if(linkmode != LinkExternal) - sh->addr = sect->vaddr; - sh->addralign = sect->align; - sh->size = sect->length; - sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr; - - return sh; -} - -ElfShdr* -elfshreloc(Section *sect) -{ - int typ; - ElfShdr *sh; - char *prefix; - char buf[100]; - - // If main section is SHT_NOBITS, nothing to relocate. - // Also nothing to relocate in .shstrtab. - if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen) - return nil; - if(strcmp(sect->name, ".shstrtab") == 0 || strcmp(sect->name, ".tbss") == 0) - return nil; - - if(thearch.thechar == '6' || thearch.thechar == '9') { - prefix = ".rela"; - typ = SHT_RELA; - } else { - prefix = ".rel"; - typ = SHT_REL; - } - - snprint(buf, sizeof buf, "%s%s", prefix, sect->name); - sh = elfshname(buf); - sh->type = typ; - sh->entsize = thearch.regsize*(2+(typ==SHT_RELA)); - sh->link = elfshname(".symtab")->shnum; - sh->info = ((ElfShdr*)sect->elfsect)->shnum; - sh->off = sect->reloff; - sh->size = sect->rellen; - sh->addralign = thearch.regsize; - return sh; -} - -void -elfrelocsect(Section *sect, LSym *first) -{ - int ri; - LSym *sym; - int32 eaddr; - Reloc *r; - - // If main section is SHT_NOBITS, nothing to relocate. - // Also nothing to relocate in .shstrtab. - if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen) - return; - if(strcmp(sect->name, ".shstrtab") == 0) - return; - - sect->reloff = cpos(); - for(sym = first; sym != nil; sym = sym->next) { - if(!sym->reachable) - continue; - if(sym->value >= sect->vaddr) - break; - } - - eaddr = sect->vaddr + sect->length; - for(; sym != nil; sym = sym->next) { - if(!sym->reachable) - continue; - if(sym->value >= eaddr) - break; - ctxt->cursym = sym; - - for(ri=0; rinr; ri++) { - r = &sym->r[ri]; - if(r->done) - continue; - if(r->xsym == nil) { - diag("missing xsym in relocation"); - continue; - } - if(r->xsym->elfsym == 0) - diag("reloc %d to non-elf symbol %s (outer=%s) %d", r->type, r->sym->name, r->xsym->name, r->sym->type); - if(thearch.elfreloc1(r, sym->value+r->off - sect->vaddr) < 0) - diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name); - } - } - - sect->rellen = cpos() - sect->reloff; -} - -void -elfemitreloc(void) -{ - Section *sect; - - while(cpos()&7) - cput(0); - - elfrelocsect(segtext.sect, ctxt->textp); - for(sect=segtext.sect->next; sect!=nil; sect=sect->next) - elfrelocsect(sect, datap); - for(sect=segrodata.sect; sect!=nil; sect=sect->next) - elfrelocsect(sect, datap); - for(sect=segdata.sect; sect!=nil; sect=sect->next) - elfrelocsect(sect, datap); -} - -void -doelf(void) -{ - LSym *s, *shstrtab, *dynstr; - - if(!iself) - return; - - /* predefine strings we need for section headers */ - shstrtab = linklookup(ctxt, ".shstrtab", 0); - shstrtab->type = SELFROSECT; - shstrtab->reachable = 1; - - addstring(shstrtab, ""); - addstring(shstrtab, ".text"); - addstring(shstrtab, ".noptrdata"); - addstring(shstrtab, ".data"); - addstring(shstrtab, ".bss"); - addstring(shstrtab, ".noptrbss"); - // generate .tbss section (except for OpenBSD where it's not supported) - // for dynamic internal linker or external linking, so that various - // binutils could correctly calculate PT_TLS size. - // see http://golang.org/issue/5200. - if(HEADTYPE != Hopenbsd) - if(!debug['d'] || linkmode == LinkExternal) - addstring(shstrtab, ".tbss"); - if(HEADTYPE == Hnetbsd) - addstring(shstrtab, ".note.netbsd.ident"); - if(HEADTYPE == Hopenbsd) - addstring(shstrtab, ".note.openbsd.ident"); - if(buildinfolen > 0) - addstring(shstrtab, ".note.gnu.build-id"); - addstring(shstrtab, ".elfdata"); - addstring(shstrtab, ".rodata"); - addstring(shstrtab, ".typelink"); - addstring(shstrtab, ".gosymtab"); - addstring(shstrtab, ".gopclntab"); - - if(linkmode == LinkExternal) { - debug_s = debug['s']; - debug['s'] = 0; - debug['d'] = 1; - - if(thearch.thechar == '6' || thearch.thechar == '9') { - addstring(shstrtab, ".rela.text"); - addstring(shstrtab, ".rela.rodata"); - addstring(shstrtab, ".rela.typelink"); - addstring(shstrtab, ".rela.gosymtab"); - addstring(shstrtab, ".rela.gopclntab"); - addstring(shstrtab, ".rela.noptrdata"); - addstring(shstrtab, ".rela.data"); - } else { - addstring(shstrtab, ".rel.text"); - addstring(shstrtab, ".rel.rodata"); - addstring(shstrtab, ".rel.typelink"); - addstring(shstrtab, ".rel.gosymtab"); - addstring(shstrtab, ".rel.gopclntab"); - addstring(shstrtab, ".rel.noptrdata"); - addstring(shstrtab, ".rel.data"); - } - // add a .note.GNU-stack section to mark the stack as non-executable - addstring(shstrtab, ".note.GNU-stack"); - } - - if(flag_shared) { - addstring(shstrtab, ".init_array"); - if(thearch.thechar == '6' || thearch.thechar == '9') - addstring(shstrtab, ".rela.init_array"); - else - addstring(shstrtab, ".rel.init_array"); - } - - if(!debug['s']) { - addstring(shstrtab, ".symtab"); - addstring(shstrtab, ".strtab"); - dwarfaddshstrings(shstrtab); - } - addstring(shstrtab, ".shstrtab"); - - if(!debug['d']) { /* -d suppresses dynamic loader format */ - addstring(shstrtab, ".interp"); - addstring(shstrtab, ".hash"); - addstring(shstrtab, ".got"); - if(thearch.thechar == '9') - addstring(shstrtab, ".glink"); - addstring(shstrtab, ".got.plt"); - addstring(shstrtab, ".dynamic"); - addstring(shstrtab, ".dynsym"); - addstring(shstrtab, ".dynstr"); - if(thearch.thechar == '6' || thearch.thechar == '9') { - addstring(shstrtab, ".rela"); - addstring(shstrtab, ".rela.plt"); - } else { - addstring(shstrtab, ".rel"); - addstring(shstrtab, ".rel.plt"); - } - addstring(shstrtab, ".plt"); - addstring(shstrtab, ".gnu.version"); - addstring(shstrtab, ".gnu.version_r"); - - /* dynamic symbol table - first entry all zeros */ - s = linklookup(ctxt, ".dynsym", 0); - s->type = SELFROSECT; - s->reachable = 1; - if(thearch.thechar == '6' || thearch.thechar == '9') - s->size += ELF64SYMSIZE; - else - s->size += ELF32SYMSIZE; - - /* dynamic string table */ - s = linklookup(ctxt, ".dynstr", 0); - s->type = SELFROSECT; - s->reachable = 1; - if(s->size == 0) - addstring(s, ""); - dynstr = s; - - /* relocation table */ - if(thearch.thechar == '6' || thearch.thechar == '9') - s = linklookup(ctxt, ".rela", 0); - else - s = linklookup(ctxt, ".rel", 0); - s->reachable = 1; - s->type = SELFROSECT; - - /* global offset table */ - s = linklookup(ctxt, ".got", 0); - s->reachable = 1; - s->type = SELFGOT; // writable - - /* ppc64 glink resolver */ - if(thearch.thechar == '9') { - s = linklookup(ctxt, ".glink", 0); - s->reachable = 1; - s->type = SELFRXSECT; - } - - /* hash */ - s = linklookup(ctxt, ".hash", 0); - s->reachable = 1; - s->type = SELFROSECT; - - s = linklookup(ctxt, ".got.plt", 0); - s->reachable = 1; - s->type = SELFSECT; // writable - - s = linklookup(ctxt, ".plt", 0); - s->reachable = 1; - if(thearch.thechar == '9') - // In the ppc64 ABI, .plt is a data section - // written by the dynamic linker. - s->type = SELFSECT; - else - s->type = SELFRXSECT; - - thearch.elfsetupplt(); - - if(thearch.thechar == '6' || thearch.thechar == '9') - s = linklookup(ctxt, ".rela.plt", 0); - else - s = linklookup(ctxt, ".rel.plt", 0); - s->reachable = 1; - s->type = SELFROSECT; - - s = linklookup(ctxt, ".gnu.version", 0); - s->reachable = 1; - s->type = SELFROSECT; - - s = linklookup(ctxt, ".gnu.version_r", 0); - s->reachable = 1; - s->type = SELFROSECT; - - /* define dynamic elf table */ - s = linklookup(ctxt, ".dynamic", 0); - s->reachable = 1; - s->type = SELFSECT; // writable - - /* - * .dynamic table - */ - elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0)); - elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0)); - if(thearch.thechar == '6' || thearch.thechar == '9') - elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE); - else - elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE); - elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0)); - elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0)); - if(thearch.thechar == '6' || thearch.thechar == '9') { - elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0)); - elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0)); - elfwritedynent(s, DT_RELAENT, ELF64RELASIZE); - } else { - elfwritedynentsym(s, DT_REL, linklookup(ctxt, ".rel", 0)); - elfwritedynentsymsize(s, DT_RELSZ, linklookup(ctxt, ".rel", 0)); - elfwritedynent(s, DT_RELENT, ELF32RELSIZE); - } - if(rpath) - elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath)); - - if(thearch.thechar == '9') - elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".plt", 0)); - else - elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0)); - - if(thearch.thechar == '9') - elfwritedynent(s, DT_PPC64_OPT, 0); - - // Solaris dynamic linker can't handle an empty .rela.plt if - // DT_JMPREL is emitted so we have to defer generation of DT_PLTREL, - // DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the - // size of .rel(a).plt section. - elfwritedynent(s, DT_DEBUG, 0); - - // Do not write DT_NULL. elfdynhash will finish it. - } -} - -void -shsym(ElfShdr *sh, LSym *s) -{ - vlong addr; - addr = symaddr(s); - if(sh->flags&SHF_ALLOC) - sh->addr = addr; - sh->off = datoff(addr); - sh->size = s->size; -} - -void -phsh(ElfPhdr *ph, ElfShdr *sh) -{ - ph->vaddr = sh->addr; - ph->paddr = ph->vaddr; - ph->off = sh->off; - ph->filesz = sh->size; - ph->memsz = sh->size; - ph->align = sh->addralign; -} - -void -asmbelfsetup(void) -{ - Section *sect; - - /* This null SHdr must appear before all others */ - elfshname(""); - - for(sect=segtext.sect; sect!=nil; sect=sect->next) - elfshalloc(sect); - for(sect=segrodata.sect; sect!=nil; sect=sect->next) - elfshalloc(sect); - for(sect=segdata.sect; sect!=nil; sect=sect->next) - elfshalloc(sect); -} - -void -asmbelf(vlong symo) -{ - vlong a, o; - vlong startva, resoff; - ElfEhdr *eh; - ElfPhdr *ph, *pph, *pnote; - ElfShdr *sh; - Section *sect; - - eh = getElfEhdr(); - switch(thearch.thechar) { - default: - diag("unknown architecture in asmbelf"); - errorexit(); - case '5': - eh->machine = EM_ARM; - break; - case '6': - eh->machine = EM_X86_64; - break; - case '8': - eh->machine = EM_386; - break; - case '9': - eh->machine = EM_PPC64; - break; - } - - startva = INITTEXT - HEADR; - resoff = ELFRESERVE; - - pph = nil; - if(linkmode == LinkExternal) { - /* skip program headers */ - eh->phoff = 0; - eh->phentsize = 0; - goto elfobj; - } - - /* program header info */ - pph = newElfPhdr(); - pph->type = PT_PHDR; - pph->flags = PF_R; - pph->off = eh->ehsize; - pph->vaddr = INITTEXT - HEADR + pph->off; - pph->paddr = INITTEXT - HEADR + pph->off; - pph->align = INITRND; - - /* - * PHDR must be in a loaded segment. Adjust the text - * segment boundaries downwards to include it. - * Except on NaCl where it must not be loaded. - */ - if(HEADTYPE != Hnacl) { - o = segtext.vaddr - pph->vaddr; - segtext.vaddr -= o; - segtext.length += o; - o = segtext.fileoff - pph->off; - segtext.fileoff -= o; - segtext.filelen += o; - } - - if(!debug['d']) { - /* interpreter */ - sh = elfshname(".interp"); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - if(interpreter == nil) { - switch(HEADTYPE) { - case Hlinux: - interpreter = thearch.linuxdynld; - break; - case Hfreebsd: - interpreter = thearch.freebsddynld; - break; - case Hnetbsd: - interpreter = thearch.netbsddynld; - break; - case Hopenbsd: - interpreter = thearch.openbsddynld; - break; - case Hdragonfly: - interpreter = thearch.dragonflydynld; - break; - case Hsolaris: - interpreter = thearch.solarisdynld; - break; - } - } - resoff -= elfinterp(sh, startva, resoff, interpreter); - - ph = newElfPhdr(); - ph->type = PT_INTERP; - ph->flags = PF_R; - phsh(ph, sh); - } - - pnote = nil; - if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) { - sh = nil; - switch(HEADTYPE) { - case Hnetbsd: - sh = elfshname(".note.netbsd.ident"); - resoff -= elfnetbsdsig(sh, startva, resoff); - break; - case Hopenbsd: - sh = elfshname(".note.openbsd.ident"); - resoff -= elfopenbsdsig(sh, startva, resoff); - break; - } - - pnote = newElfPhdr(); - pnote->type = PT_NOTE; - pnote->flags = PF_R; - phsh(pnote, sh); - } - - if(buildinfolen > 0) { - sh = elfshname(".note.gnu.build-id"); - resoff -= elfbuildinfo(sh, startva, resoff); - - if(pnote == nil) { - pnote = newElfPhdr(); - pnote->type = PT_NOTE; - pnote->flags = PF_R; - } - phsh(pnote, sh); - } - - // Additions to the reserved area must be above this line. - USED(resoff); - - elfphload(&segtext); - if(segrodata.sect != nil) - elfphload(&segrodata); - elfphload(&segdata); - - /* Dynamic linking sections */ - if(!debug['d']) { /* -d suppresses dynamic loader format */ - sh = elfshname(".dynsym"); - sh->type = SHT_DYNSYM; - sh->flags = SHF_ALLOC; - if(elf64) - sh->entsize = ELF64SYMSIZE; - else - sh->entsize = ELF32SYMSIZE; - sh->addralign = thearch.regsize; - sh->link = elfshname(".dynstr")->shnum; - // sh->info = index of first non-local symbol (number of local symbols) - shsym(sh, linklookup(ctxt, ".dynsym", 0)); - - sh = elfshname(".dynstr"); - sh->type = SHT_STRTAB; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - shsym(sh, linklookup(ctxt, ".dynstr", 0)); - - if(elfverneed) { - sh = elfshname(".gnu.version"); - sh->type = SHT_GNU_VERSYM; - sh->flags = SHF_ALLOC; - sh->addralign = 2; - sh->link = elfshname(".dynsym")->shnum; - sh->entsize = 2; - shsym(sh, linklookup(ctxt, ".gnu.version", 0)); - - sh = elfshname(".gnu.version_r"); - sh->type = SHT_GNU_VERNEED; - sh->flags = SHF_ALLOC; - sh->addralign = thearch.regsize; - sh->info = elfverneed; - sh->link = elfshname(".dynstr")->shnum; - shsym(sh, linklookup(ctxt, ".gnu.version_r", 0)); - } - - switch(eh->machine) { - case EM_X86_64: - case EM_PPC64: - sh = elfshname(".rela.plt"); - sh->type = SHT_RELA; - sh->flags = SHF_ALLOC; - sh->entsize = ELF64RELASIZE; - sh->addralign = thearch.regsize; - sh->link = elfshname(".dynsym")->shnum; - sh->info = elfshname(".plt")->shnum; - shsym(sh, linklookup(ctxt, ".rela.plt", 0)); - - sh = elfshname(".rela"); - sh->type = SHT_RELA; - sh->flags = SHF_ALLOC; - sh->entsize = ELF64RELASIZE; - sh->addralign = 8; - sh->link = elfshname(".dynsym")->shnum; - shsym(sh, linklookup(ctxt, ".rela", 0)); - break; - - default: - sh = elfshname(".rel.plt"); - sh->type = SHT_REL; - sh->flags = SHF_ALLOC; - sh->entsize = ELF32RELSIZE; - sh->addralign = 4; - sh->link = elfshname(".dynsym")->shnum; - shsym(sh, linklookup(ctxt, ".rel.plt", 0)); - - sh = elfshname(".rel"); - sh->type = SHT_REL; - sh->flags = SHF_ALLOC; - sh->entsize = ELF32RELSIZE; - sh->addralign = 4; - sh->link = elfshname(".dynsym")->shnum; - shsym(sh, linklookup(ctxt, ".rel", 0)); - break; - } - - if(eh->machine == EM_PPC64) { - sh = elfshname(".glink"); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC+SHF_EXECINSTR; - sh->addralign = 4; - shsym(sh, linklookup(ctxt, ".glink", 0)); - } - - sh = elfshname(".plt"); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC+SHF_EXECINSTR; - if(eh->machine == EM_X86_64) - sh->entsize = 16; - else if(eh->machine == EM_PPC64) { - // On ppc64, this is just a table of addresses - // filled by the dynamic linker - sh->type = SHT_NOBITS; - sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = 8; - } else - sh->entsize = 4; - sh->addralign = sh->entsize; - shsym(sh, linklookup(ctxt, ".plt", 0)); - - // On ppc64, .got comes from the input files, so don't - // create it here, and .got.plt is not used. - if(eh->machine != EM_PPC64) { - sh = elfshname(".got"); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = thearch.regsize; - sh->addralign = thearch.regsize; - shsym(sh, linklookup(ctxt, ".got", 0)); - - sh = elfshname(".got.plt"); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = thearch.regsize; - sh->addralign = thearch.regsize; - shsym(sh, linklookup(ctxt, ".got.plt", 0)); - } - - sh = elfshname(".hash"); - sh->type = SHT_HASH; - sh->flags = SHF_ALLOC; - sh->entsize = 4; - sh->addralign = thearch.regsize; - sh->link = elfshname(".dynsym")->shnum; - shsym(sh, linklookup(ctxt, ".hash", 0)); - - /* sh and PT_DYNAMIC for .dynamic section */ - sh = elfshname(".dynamic"); - sh->type = SHT_DYNAMIC; - sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = 2*thearch.regsize; - sh->addralign = thearch.regsize; - sh->link = elfshname(".dynstr")->shnum; - shsym(sh, linklookup(ctxt, ".dynamic", 0)); - ph = newElfPhdr(); - ph->type = PT_DYNAMIC; - ph->flags = PF_R + PF_W; - phsh(ph, sh); - - /* - * Thread-local storage segment (really just size). - */ - // Do not emit PT_TLS for OpenBSD since ld.so(1) does - // not currently support it. This is handled - // appropriately in runtime/cgo. - if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) { - ph = newElfPhdr(); - ph->type = PT_TLS; - ph->flags = PF_R; - ph->memsz = -ctxt->tlsoffset; - ph->align = thearch.regsize; - } - } - - if(HEADTYPE == Hlinux) { - ph = newElfPhdr(); - ph->type = PT_GNU_STACK; - ph->flags = PF_W+PF_R; - ph->align = thearch.regsize; - - ph = newElfPhdr(); - ph->type = PT_PAX_FLAGS; - ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled - ph->align = thearch.regsize; - } - -elfobj: - sh = elfshname(".shstrtab"); - sh->type = SHT_STRTAB; - sh->addralign = 1; - shsym(sh, linklookup(ctxt, ".shstrtab", 0)); - eh->shstrndx = sh->shnum; - - // put these sections early in the list - if(!debug['s']) { - elfshname(".symtab"); - elfshname(".strtab"); - } - - for(sect=segtext.sect; sect!=nil; sect=sect->next) - elfshbits(sect); - for(sect=segrodata.sect; sect!=nil; sect=sect->next) - elfshbits(sect); - for(sect=segdata.sect; sect!=nil; sect=sect->next) - elfshbits(sect); - - if(linkmode == LinkExternal) { - for(sect=segtext.sect; sect!=nil; sect=sect->next) - elfshreloc(sect); - for(sect=segrodata.sect; sect!=nil; sect=sect->next) - elfshreloc(sect); - for(sect=segdata.sect; sect!=nil; sect=sect->next) - elfshreloc(sect); - // add a .note.GNU-stack section to mark the stack as non-executable - sh = elfshname(".note.GNU-stack"); - sh->type = SHT_PROGBITS; - sh->addralign = 1; - sh->flags = 0; - } - - // generate .tbss section for dynamic internal linking (except for OpenBSD) - // external linking generates .tbss in data.c - if(linkmode == LinkInternal && !debug['d'] && HEADTYPE != Hopenbsd) { - sh = elfshname(".tbss"); - sh->type = SHT_NOBITS; - sh->addralign = thearch.regsize; - sh->size = -ctxt->tlsoffset; - sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE; - } - - if(!debug['s']) { - sh = elfshname(".symtab"); - sh->type = SHT_SYMTAB; - sh->off = symo; - sh->size = symsize; - sh->addralign = thearch.regsize; - sh->entsize = 8+2*thearch.regsize; - sh->link = elfshname(".strtab")->shnum; - sh->info = elfglobalsymndx; - - sh = elfshname(".strtab"); - sh->type = SHT_STRTAB; - sh->off = symo+symsize; - sh->size = elfstrsize; - sh->addralign = 1; - - dwarfaddelfheaders(); - } - - /* Main header */ - eh->ident[EI_MAG0] = '\177'; - eh->ident[EI_MAG1] = 'E'; - eh->ident[EI_MAG2] = 'L'; - eh->ident[EI_MAG3] = 'F'; - if(HEADTYPE == Hfreebsd) - eh->ident[EI_OSABI] = ELFOSABI_FREEBSD; - else if(HEADTYPE == Hnetbsd) - eh->ident[EI_OSABI] = ELFOSABI_NETBSD; - else if(HEADTYPE == Hopenbsd) - eh->ident[EI_OSABI] = ELFOSABI_OPENBSD; - else if(HEADTYPE == Hdragonfly) - eh->ident[EI_OSABI] = ELFOSABI_NONE; - if(elf64) - eh->ident[EI_CLASS] = ELFCLASS64; - else - eh->ident[EI_CLASS] = ELFCLASS32; - if(ctxt->arch->endian == BigEndian) - eh->ident[EI_DATA] = ELFDATA2MSB; - else - eh->ident[EI_DATA] = ELFDATA2LSB; - eh->ident[EI_VERSION] = EV_CURRENT; - - if(linkmode == LinkExternal) - eh->type = ET_REL; - else - eh->type = ET_EXEC; - - if(linkmode != LinkExternal) - eh->entry = entryvalue(); - - eh->version = EV_CURRENT; - - if(pph != nil) { - pph->filesz = eh->phnum * eh->phentsize; - pph->memsz = pph->filesz; - } - - cseek(0); - a = 0; - a += elfwritehdr(); - a += elfwritephdrs(); - a += elfwriteshdrs(); - if(!debug['d']) - a += elfwriteinterp(); - if(linkmode != LinkExternal) { - if(HEADTYPE == Hnetbsd) - a += elfwritenetbsdsig(); - if(HEADTYPE == Hopenbsd) - a += elfwriteopenbsdsig(); - if(buildinfolen > 0) - a += elfwritebuildinfo(); - } - if(a > ELFRESERVE) - diag("ELFRESERVE too small: %lld > %d", a, ELFRESERVE); -} - -uint32 -ELF32_R_SYM(uint32 info) -{ - return info>>8; -} - -uint32 -ELF32_R_TYPE(uint32 info) -{ - return (uint8)info; -} - -uint32 -ELF32_R_INFO(uint32 sym, uint32 type) -{ - return sym<<8 | type; -} - -uint8 -ELF32_ST_BIND(uint8 info) -{ - return info>>4; -} - -uint8 -ELF32_ST_TYPE(uint8 info) -{ - return info & 0xf; -} - -uint8 -ELF32_ST_INFO(uint8 bind, uint8 type) -{ - return bind<<4 | type&0xf; -} - -uint8 -ELF32_ST_VISIBILITY(uint8 oth) -{ - return oth & 3; -} - -uint32 -ELF64_R_SYM(uint64 info) -{ - return info>>32; -} - -uint32 -ELF64_R_TYPE(uint64 info) -{ - return info; -} - -uint64 -ELF64_R_INFO(uint32 sym, uint32 type) -{ - return (uint64)sym<<32 | type; -} - -uint8 -ELF64_ST_BIND(uint8 info) -{ - return info>>4; -} - -uint8 -ELF64_ST_TYPE(uint8 info) -{ - return info & 0xf; -} - -uint8 -ELF64_ST_INFO(uint8 bind, uint8 type) -{ - return bind<<4 | type&0xf; -} - -uint8 -ELF64_ST_VISIBILITY(uint8 oth) -{ - return oth & 3; -} diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h deleted file mode 100644 index 378d246e1d..0000000000 --- a/src/cmd/ld/elf.h +++ /dev/null @@ -1,857 +0,0 @@ -/* - * Derived from: - * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $ - * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $ - * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $ - * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $ - * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $ - * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $ - * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $ - * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $ - * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $ - * - * Copyright (c) 1996-1998 John D. Polstra. All rights reserved. - * Copyright (c) 2001 David E. O'Brien - * Portions Copyright 2009 The Go Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -/* - * ELF definitions that are independent of architecture or word size. - */ - -/* - * Note header. The ".note" section contains an array of notes. Each - * begins with this header, aligned to a word boundary. Immediately - * following the note header is n_namesz bytes of name, padded to the - * next word boundary. Then comes n_descsz bytes of descriptor, again - * padded to a word boundary. The values of n_namesz and n_descsz do - * not include the padding. - */ - -typedef struct Elf_Note Elf_Note; -struct Elf_Note { - uint32 n_namesz; /* Length of name. */ - uint32 n_descsz; /* Length of descriptor. */ - uint32 n_type; /* Type of this note. */ -}; - -enum { -/* Indexes into the e_ident array. Keep synced with - http://www.sco.com/developer/gabi/ch4.eheader.html */ - EI_MAG0 = 0, /* Magic number, byte 0. */ - EI_MAG1 = 1, /* Magic number, byte 1. */ - EI_MAG2 = 2, /* Magic number, byte 2. */ - EI_MAG3 = 3, /* Magic number, byte 3. */ - EI_CLASS = 4, /* Class of machine. */ - EI_DATA = 5, /* Data format. */ - EI_VERSION = 6, /* ELF format version. */ - EI_OSABI = 7, /* Operating system / ABI identification */ - EI_ABIVERSION = 8, /* ABI version */ - OLD_EI_BRAND = 8, /* Start of architecture identification. */ - EI_PAD = 9, /* Start of padding (per SVR4 ABI). */ - EI_NIDENT = 16, /* Size of e_ident array. */ - -/* Values for the magic number bytes. */ - ELFMAG0 = 0x7f, - ELFMAG1 = 'E', - ELFMAG2 = 'L', - ELFMAG3 = 'F', - SELFMAG = 4, /* magic string size */ - -/* Values for e_ident[EI_VERSION] and e_version. */ - EV_NONE = 0, - EV_CURRENT = 1, - -/* Values for e_ident[EI_CLASS]. */ - ELFCLASSNONE = 0, /* Unknown class. */ - ELFCLASS32 = 1, /* 32-bit architecture. */ - ELFCLASS64 = 2, /* 64-bit architecture. */ - -/* Values for e_ident[EI_DATA]. */ - ELFDATANONE = 0, /* Unknown data format. */ - ELFDATA2LSB = 1, /* 2's complement little-endian. */ - ELFDATA2MSB = 2, /* 2's complement big-endian. */ - -/* Values for e_ident[EI_OSABI]. */ - ELFOSABI_NONE = 0, /* UNIX System V ABI */ - ELFOSABI_HPUX = 1, /* HP-UX operating system */ - ELFOSABI_NETBSD = 2, /* NetBSD */ - ELFOSABI_LINUX = 3, /* GNU/Linux */ - ELFOSABI_HURD = 4, /* GNU/Hurd */ - ELFOSABI_86OPEN = 5, /* 86Open common IA32 ABI */ - ELFOSABI_SOLARIS = 6, /* Solaris */ - ELFOSABI_AIX = 7, /* AIX */ - ELFOSABI_IRIX = 8, /* IRIX */ - ELFOSABI_FREEBSD = 9, /* FreeBSD */ - ELFOSABI_TRU64 = 10, /* TRU64 UNIX */ - ELFOSABI_MODESTO = 11, /* Novell Modesto */ - ELFOSABI_OPENBSD = 12, /* OpenBSD */ - ELFOSABI_OPENVMS = 13, /* Open VMS */ - ELFOSABI_NSK = 14, /* HP Non-Stop Kernel */ - ELFOSABI_ARM = 97, /* ARM */ - ELFOSABI_STANDALONE = 255, /* Standalone (embedded) application */ - - ELFOSABI_SYSV = ELFOSABI_NONE, /* symbol used in old spec */ - ELFOSABI_MONTEREY = ELFOSABI_AIX, /* Monterey */ - -/* Values for e_type. */ - ET_NONE = 0, /* Unknown type. */ - ET_REL = 1, /* Relocatable. */ - ET_EXEC = 2, /* Executable. */ - ET_DYN = 3, /* Shared object. */ - ET_CORE = 4, /* Core file. */ - ET_LOOS = 0xfe00, /* First operating system specific. */ - ET_HIOS = 0xfeff, /* Last operating system-specific. */ - ET_LOPROC = 0xff00, /* First processor-specific. */ - ET_HIPROC = 0xffff, /* Last processor-specific. */ - -/* Values for e_machine. */ - EM_NONE = 0, /* Unknown machine. */ - EM_M32 = 1, /* AT&T WE32100. */ - EM_SPARC = 2, /* Sun SPARC. */ - EM_386 = 3, /* Intel i386. */ - EM_68K = 4, /* Motorola 68000. */ - EM_88K = 5, /* Motorola 88000. */ - EM_860 = 7, /* Intel i860. */ - EM_MIPS = 8, /* MIPS R3000 Big-Endian only. */ - EM_S370 = 9, /* IBM System/370. */ - EM_MIPS_RS3_LE = 10, /* MIPS R3000 Little-Endian. */ - EM_PARISC = 15, /* HP PA-RISC. */ - EM_VPP500 = 17, /* Fujitsu VPP500. */ - EM_SPARC32PLUS = 18, /* SPARC v8plus. */ - EM_960 = 19, /* Intel 80960. */ - EM_PPC = 20, /* PowerPC 32-bit. */ - EM_PPC64 = 21, /* PowerPC 64-bit. */ - EM_S390 = 22, /* IBM System/390. */ - EM_V800 = 36, /* NEC V800. */ - EM_FR20 = 37, /* Fujitsu FR20. */ - EM_RH32 = 38, /* TRW RH-32. */ - EM_RCE = 39, /* Motorola RCE. */ - EM_ARM = 40, /* ARM. */ - EM_SH = 42, /* Hitachi SH. */ - EM_SPARCV9 = 43, /* SPARC v9 64-bit. */ - EM_TRICORE = 44, /* Siemens TriCore embedded processor. */ - EM_ARC = 45, /* Argonaut RISC Core. */ - EM_H8_300 = 46, /* Hitachi H8/300. */ - EM_H8_300H = 47, /* Hitachi H8/300H. */ - EM_H8S = 48, /* Hitachi H8S. */ - EM_H8_500 = 49, /* Hitachi H8/500. */ - EM_IA_64 = 50, /* Intel IA-64 Processor. */ - EM_MIPS_X = 51, /* Stanford MIPS-X. */ - EM_COLDFIRE = 52, /* Motorola ColdFire. */ - EM_68HC12 = 53, /* Motorola M68HC12. */ - EM_MMA = 54, /* Fujitsu MMA. */ - EM_PCP = 55, /* Siemens PCP. */ - EM_NCPU = 56, /* Sony nCPU. */ - EM_NDR1 = 57, /* Denso NDR1 microprocessor. */ - EM_STARCORE = 58, /* Motorola Star*Core processor. */ - EM_ME16 = 59, /* Toyota ME16 processor. */ - EM_ST100 = 60, /* STMicroelectronics ST100 processor. */ - EM_TINYJ = 61, /* Advanced Logic Corp. TinyJ processor. */ - EM_X86_64 = 62, /* Advanced Micro Devices x86-64 */ - -/* Non-standard or deprecated. */ - EM_486 = 6, /* Intel i486. */ - EM_MIPS_RS4_BE = 10, /* MIPS R4000 Big-Endian */ - EM_ALPHA_STD = 41, /* Digital Alpha (standard value). */ - EM_ALPHA = 0x9026, /* Alpha (written in the absence of an ABI) */ - -/* Special section indexes. */ - SHN_UNDEF = 0, /* Undefined, missing, irrelevant. */ - SHN_LORESERVE = 0xff00, /* First of reserved range. */ - SHN_LOPROC = 0xff00, /* First processor-specific. */ - SHN_HIPROC = 0xff1f, /* Last processor-specific. */ - SHN_LOOS = 0xff20, /* First operating system-specific. */ - SHN_HIOS = 0xff3f, /* Last operating system-specific. */ - SHN_ABS = 0xfff1, /* Absolute values. */ - SHN_COMMON = 0xfff2, /* Common data. */ - SHN_XINDEX = 0xffff, /* Escape -- index stored elsewhere. */ - SHN_HIRESERVE = 0xffff, /* Last of reserved range. */ - -/* sh_type */ - SHT_NULL = 0, /* inactive */ - SHT_PROGBITS = 1, /* program defined information */ - SHT_SYMTAB = 2, /* symbol table section */ - SHT_STRTAB = 3, /* string table section */ - SHT_RELA = 4, /* relocation section with addends */ - SHT_HASH = 5, /* symbol hash table section */ - SHT_DYNAMIC = 6, /* dynamic section */ - SHT_NOTE = 7, /* note section */ - SHT_NOBITS = 8, /* no space section */ - SHT_REL = 9, /* relocation section - no addends */ - SHT_SHLIB = 10, /* reserved - purpose unknown */ - SHT_DYNSYM = 11, /* dynamic symbol table section */ - SHT_INIT_ARRAY = 14, /* Initialization function pointers. */ - SHT_FINI_ARRAY = 15, /* Termination function pointers. */ - SHT_PREINIT_ARRAY = 16, /* Pre-initialization function ptrs. */ - SHT_GROUP = 17, /* Section group. */ - SHT_SYMTAB_SHNDX = 18, /* Section indexes (see SHN_XINDEX). */ - SHT_LOOS = 0x60000000, /* First of OS specific semantics */ - SHT_HIOS = 0x6fffffff, /* Last of OS specific semantics */ - SHT_GNU_VERDEF = 0x6ffffffd, - SHT_GNU_VERNEED = 0x6ffffffe, - SHT_GNU_VERSYM = 0x6fffffff, - SHT_LOPROC = 0x70000000, /* reserved range for processor */ - SHT_HIPROC = 0x7fffffff, /* specific section header types */ - SHT_LOUSER = 0x80000000, /* reserved range for application */ - SHT_HIUSER = 0xffffffff, /* specific indexes */ - -/* Flags for sh_flags. */ - SHF_WRITE = 0x1, /* Section contains writable data. */ - SHF_ALLOC = 0x2, /* Section occupies memory. */ - SHF_EXECINSTR = 0x4, /* Section contains instructions. */ - SHF_MERGE = 0x10, /* Section may be merged. */ - SHF_STRINGS = 0x20, /* Section contains strings. */ - SHF_INFO_LINK = 0x40, /* sh_info holds section index. */ - SHF_LINK_ORDER = 0x80, /* Special ordering requirements. */ - SHF_OS_NONCONFORMING = 0x100, /* OS-specific processing required. */ - SHF_GROUP = 0x200, /* Member of section group. */ - SHF_TLS = 0x400, /* Section contains TLS data. */ - SHF_MASKOS = 0x0ff00000, /* OS-specific semantics. */ - SHF_MASKPROC = 0xf0000000, /* Processor-specific semantics. */ - -/* Values for p_type. */ - PT_NULL = 0, /* Unused entry. */ - PT_LOAD = 1, /* Loadable segment. */ - PT_DYNAMIC = 2, /* Dynamic linking information segment. */ - PT_INTERP = 3, /* Pathname of interpreter. */ - PT_NOTE = 4, /* Auxiliary information. */ - PT_SHLIB = 5, /* Reserved (not used). */ - PT_PHDR = 6, /* Location of program header itself. */ - PT_TLS = 7, /* Thread local storage segment */ - PT_LOOS = 0x60000000, /* First OS-specific. */ - PT_HIOS = 0x6fffffff, /* Last OS-specific. */ - PT_LOPROC = 0x70000000, /* First processor-specific type. */ - PT_HIPROC = 0x7fffffff, /* Last processor-specific type. */ - PT_GNU_STACK = 0x6474e551, - PT_PAX_FLAGS = 0x65041580, - -/* Values for p_flags. */ - PF_X = 0x1, /* Executable. */ - PF_W = 0x2, /* Writable. */ - PF_R = 0x4, /* Readable. */ - PF_MASKOS = 0x0ff00000, /* Operating system-specific. */ - PF_MASKPROC = 0xf0000000, /* Processor-specific. */ - -/* Values for d_tag. */ - DT_NULL = 0, /* Terminating entry. */ -/* String table offset of a needed shared library. */ - DT_NEEDED = 1, - DT_PLTRELSZ = 2, /* Total size in bytes of PLT relocations. */ - DT_PLTGOT = 3, /* Processor-dependent address. */ - DT_HASH = 4, /* Address of symbol hash table. */ - DT_STRTAB = 5, /* Address of string table. */ - DT_SYMTAB = 6, /* Address of symbol table. */ - DT_RELA = 7, /* Address of ElfNN_Rela relocations. */ - DT_RELASZ = 8, /* Total size of ElfNN_Rela relocations. */ - DT_RELAENT = 9, /* Size of each ElfNN_Rela relocation entry. */ - DT_STRSZ = 10, /* Size of string table. */ - DT_SYMENT = 11, /* Size of each symbol table entry. */ - DT_INIT = 12, /* Address of initialization function. */ - DT_FINI = 13, /* Address of finalization function. */ -/* String table offset of shared object name. */ - DT_SONAME = 14, - DT_RPATH = 15, /* String table offset of library path. [sup] */ - DT_SYMBOLIC = 16, /* Indicates "symbolic" linking. [sup] */ - DT_REL = 17, /* Address of ElfNN_Rel relocations. */ - DT_RELSZ = 18, /* Total size of ElfNN_Rel relocations. */ - DT_RELENT = 19, /* Size of each ElfNN_Rel relocation. */ - DT_PLTREL = 20, /* Type of relocation used for PLT. */ - DT_DEBUG = 21, /* Reserved (not used). */ -/* Indicates there may be relocations in non-writable segments. [sup] */ - DT_TEXTREL = 22, - DT_JMPREL = 23, /* Address of PLT relocations. */ - DT_BIND_NOW = 24, /* [sup] */ -/* Address of the array of pointers to initialization functions */ - DT_INIT_ARRAY = 25, -/* Address of the array of pointers to termination functions */ - DT_FINI_ARRAY = 26, -/* Size in bytes of the array of initialization functions. */ - DT_INIT_ARRAYSZ = 27, -/* Size in bytes of the array of terminationfunctions. */ - DT_FINI_ARRAYSZ = 28, -/* String table offset of a null-terminated library search path string. */ - DT_RUNPATH = 29, - DT_FLAGS = 30, /* Object specific flag values. */ -/* Values greater than or equal to DT_ENCODING and less than - DT_LOOS follow the rules for the interpretation of the d_un - union as follows: even == 'd_ptr', even == 'd_val' or none */ - DT_ENCODING = 32, -/* Address of the array of pointers to pre-initialization functions. */ - DT_PREINIT_ARRAY = 32, -/* Size in bytes of the array of pre-initialization functions. */ - DT_PREINIT_ARRAYSZ = 33, - DT_LOOS = 0x6000000d, /* First OS-specific */ - DT_HIOS = 0x6ffff000, /* Last OS-specific */ - DT_LOPROC = 0x70000000, /* First processor-specific type. */ - DT_HIPROC = 0x7fffffff, /* Last processor-specific type. */ - - DT_VERNEED = 0x6ffffffe, - DT_VERNEEDNUM = 0x6fffffff, - DT_VERSYM = 0x6ffffff0, - - DT_PPC64_GLINK = (DT_LOPROC + 0), - DT_PPC64_OPT = (DT_LOPROC + 3), - -/* Values for DT_FLAGS */ -/* Indicates that the object being loaded may make reference to - the $ORIGIN substitution string */ - DF_ORIGIN = 0x0001, - DF_SYMBOLIC = 0x0002, /* Indicates "symbolic" linking. */ -/* Indicates there may be relocations in non-writable segments. */ - DF_TEXTREL = 0x0004, -/* Indicates that the dynamic linker should process all - relocations for the object containing this entry before - transferring control to the program. */ - DF_BIND_NOW = 0x0008, -/* Indicates that the shared object or executable contains code - using a static thread-local storage scheme. */ - DF_STATIC_TLS = 0x0010, - -/* Values for n_type. Used in core files. */ - NT_PRSTATUS = 1, /* Process status. */ - NT_FPREGSET = 2, /* Floating point registers. */ - NT_PRPSINFO = 3, /* Process state info. */ - -/* Symbol Binding - ELFNN_ST_BIND - st_info */ - STB_LOCAL = 0, /* Local symbol */ - STB_GLOBAL = 1, /* Global symbol */ - STB_WEAK = 2, /* like global - lower precedence */ - STB_LOOS = 10, /* Reserved range for operating system */ - STB_HIOS = 12, /* specific semantics. */ - STB_LOPROC = 13, /* reserved range for processor */ - STB_HIPROC = 15, /* specific semantics. */ - -/* Symbol type - ELFNN_ST_TYPE - st_info */ - STT_NOTYPE = 0, /* Unspecified type. */ - STT_OBJECT = 1, /* Data object. */ - STT_FUNC = 2, /* Function. */ - STT_SECTION = 3, /* Section. */ - STT_FILE = 4, /* Source file. */ - STT_COMMON = 5, /* Uninitialized common block. */ - STT_TLS = 6, /* TLS object. */ - STT_LOOS = 10, /* Reserved range for operating system */ - STT_HIOS = 12, /* specific semantics. */ - STT_LOPROC = 13, /* reserved range for processor */ - STT_HIPROC = 15, /* specific semantics. */ - -/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ - STV_DEFAULT = 0x0, /* Default visibility (see binding). */ - STV_INTERNAL = 0x1, /* Special meaning in relocatable objects. */ - STV_HIDDEN = 0x2, /* Not visible. */ - STV_PROTECTED = 0x3, /* Visible but not preemptible. */ - -/* Special symbol table indexes. */ - STN_UNDEF = 0, /* Undefined symbol index. */ -}; - - -/* For accessing the fields of r_info. */ -uint32 ELF32_R_SYM(uint32 info); -uint32 ELF32_R_TYPE(uint32 info); - -/* For constructing r_info from field values. */ -uint32 ELF32_R_INFO(uint32 sym, uint32 type); - -/* - * Relocation types. - */ - -enum { - R_X86_64_NONE = 0, /* No relocation. */ - R_X86_64_64 = 1, /* Add 64 bit symbol value. */ - R_X86_64_PC32 = 2, /* PC-relative 32 bit signed sym value. */ - R_X86_64_GOT32 = 3, /* PC-relative 32 bit GOT offset. */ - R_X86_64_PLT32 = 4, /* PC-relative 32 bit PLT offset. */ - R_X86_64_COPY = 5, /* Copy data from shared object. */ - R_X86_64_GLOB_DAT = 6, /* Set GOT entry to data address. */ - R_X86_64_JMP_SLOT = 7, /* Set GOT entry to code address. */ - R_X86_64_RELATIVE = 8, /* Add load address of shared object. */ - R_X86_64_GOTPCREL = 9, /* Add 32 bit signed pcrel offset to GOT. */ - R_X86_64_32 = 10, /* Add 32 bit zero extended symbol value */ - R_X86_64_32S = 11, /* Add 32 bit sign extended symbol value */ - R_X86_64_16 = 12, /* Add 16 bit zero extended symbol value */ - R_X86_64_PC16 = 13, /* Add 16 bit signed extended pc relative symbol value */ - R_X86_64_8 = 14, /* Add 8 bit zero extended symbol value */ - R_X86_64_PC8 = 15, /* Add 8 bit signed extended pc relative symbol value */ - R_X86_64_DTPMOD64 = 16, /* ID of module containing symbol */ - R_X86_64_DTPOFF64 = 17, /* Offset in TLS block */ - R_X86_64_TPOFF64 = 18, /* Offset in static TLS block */ - R_X86_64_TLSGD = 19, /* PC relative offset to GD GOT entry */ - R_X86_64_TLSLD = 20, /* PC relative offset to LD GOT entry */ - R_X86_64_DTPOFF32 = 21, /* Offset in TLS block */ - R_X86_64_GOTTPOFF = 22, /* PC relative offset to IE GOT entry */ - R_X86_64_TPOFF32 = 23, /* Offset in static TLS block */ - - R_X86_64_COUNT = 24, /* Count of defined relocation types. */ - - - R_ALPHA_NONE = 0, /* No reloc */ - R_ALPHA_REFLONG = 1, /* Direct 32 bit */ - R_ALPHA_REFQUAD = 2, /* Direct 64 bit */ - R_ALPHA_GPREL32 = 3, /* GP relative 32 bit */ - R_ALPHA_LITERAL = 4, /* GP relative 16 bit w/optimization */ - R_ALPHA_LITUSE = 5, /* Optimization hint for LITERAL */ - R_ALPHA_GPDISP = 6, /* Add displacement to GP */ - R_ALPHA_BRADDR = 7, /* PC+4 relative 23 bit shifted */ - R_ALPHA_HINT = 8, /* PC+4 relative 16 bit shifted */ - R_ALPHA_SREL16 = 9, /* PC relative 16 bit */ - R_ALPHA_SREL32 = 10, /* PC relative 32 bit */ - R_ALPHA_SREL64 = 11, /* PC relative 64 bit */ - R_ALPHA_OP_PUSH = 12, /* OP stack push */ - R_ALPHA_OP_STORE = 13, /* OP stack pop and store */ - R_ALPHA_OP_PSUB = 14, /* OP stack subtract */ - R_ALPHA_OP_PRSHIFT = 15, /* OP stack right shift */ - R_ALPHA_GPVALUE = 16, - R_ALPHA_GPRELHIGH = 17, - R_ALPHA_GPRELLOW = 18, - R_ALPHA_IMMED_GP_16 = 19, - R_ALPHA_IMMED_GP_HI32 = 20, - R_ALPHA_IMMED_SCN_HI32 = 21, - R_ALPHA_IMMED_BR_HI32 = 22, - R_ALPHA_IMMED_LO32 = 23, - R_ALPHA_COPY = 24, /* Copy symbol at runtime */ - R_ALPHA_GLOB_DAT = 25, /* Create GOT entry */ - R_ALPHA_JMP_SLOT = 26, /* Create PLT entry */ - R_ALPHA_RELATIVE = 27, /* Adjust by program base */ - - R_ALPHA_COUNT = 28, - - - R_ARM_NONE = 0, /* No relocation. */ - R_ARM_PC24 = 1, - R_ARM_ABS32 = 2, - R_ARM_REL32 = 3, - R_ARM_PC13 = 4, - R_ARM_ABS16 = 5, - R_ARM_ABS12 = 6, - R_ARM_THM_ABS5 = 7, - R_ARM_ABS8 = 8, - R_ARM_SBREL32 = 9, - R_ARM_THM_PC22 = 10, - R_ARM_THM_PC8 = 11, - R_ARM_AMP_VCALL9 = 12, - R_ARM_SWI24 = 13, - R_ARM_THM_SWI8 = 14, - R_ARM_XPC25 = 15, - R_ARM_THM_XPC22 = 16, - R_ARM_COPY = 20, /* Copy data from shared object. */ - R_ARM_GLOB_DAT = 21, /* Set GOT entry to data address. */ - R_ARM_JUMP_SLOT = 22, /* Set GOT entry to code address. */ - R_ARM_RELATIVE = 23, /* Add load address of shared object. */ - R_ARM_GOTOFF = 24, /* Add GOT-relative symbol address. */ - R_ARM_GOTPC = 25, /* Add PC-relative GOT table address. */ - R_ARM_GOT32 = 26, /* Add PC-relative GOT offset. */ - R_ARM_PLT32 = 27, /* Add PC-relative PLT offset. */ - R_ARM_CALL = 28, - R_ARM_JUMP24 = 29, - R_ARM_V4BX = 40, - R_ARM_GOT_PREL = 96, - R_ARM_GNU_VTENTRY = 100, - R_ARM_GNU_VTINHERIT = 101, - R_ARM_TLS_IE32 = 107, - R_ARM_TLS_LE32 = 108, - R_ARM_RSBREL32 = 250, - R_ARM_THM_RPC22 = 251, - R_ARM_RREL32 = 252, - R_ARM_RABS32 = 253, - R_ARM_RPC24 = 254, - R_ARM_RBASE = 255, - - R_ARM_COUNT = 38, /* Count of defined relocation types. */ - - - R_386_NONE = 0, /* No relocation. */ - R_386_32 = 1, /* Add symbol value. */ - R_386_PC32 = 2, /* Add PC-relative symbol value. */ - R_386_GOT32 = 3, /* Add PC-relative GOT offset. */ - R_386_PLT32 = 4, /* Add PC-relative PLT offset. */ - R_386_COPY = 5, /* Copy data from shared object. */ - R_386_GLOB_DAT = 6, /* Set GOT entry to data address. */ - R_386_JMP_SLOT = 7, /* Set GOT entry to code address. */ - R_386_RELATIVE = 8, /* Add load address of shared object. */ - R_386_GOTOFF = 9, /* Add GOT-relative symbol address. */ - R_386_GOTPC = 10, /* Add PC-relative GOT table address. */ - R_386_TLS_TPOFF = 14, /* Negative offset in static TLS block */ - R_386_TLS_IE = 15, /* Absolute address of GOT for -ve static TLS */ - R_386_TLS_GOTIE = 16, /* GOT entry for negative static TLS block */ - R_386_TLS_LE = 17, /* Negative offset relative to static TLS */ - R_386_TLS_GD = 18, /* 32 bit offset to GOT (index,off) pair */ - R_386_TLS_LDM = 19, /* 32 bit offset to GOT (index,zero) pair */ - R_386_TLS_GD_32 = 24, /* 32 bit offset to GOT (index,off) pair */ - R_386_TLS_GD_PUSH = 25, /* pushl instruction for Sun ABI GD sequence */ - R_386_TLS_GD_CALL = 26, /* call instruction for Sun ABI GD sequence */ - R_386_TLS_GD_POP = 27, /* popl instruction for Sun ABI GD sequence */ - R_386_TLS_LDM_32 = 28, /* 32 bit offset to GOT (index,zero) pair */ - R_386_TLS_LDM_PUSH = 29, /* pushl instruction for Sun ABI LD sequence */ - R_386_TLS_LDM_CALL = 30, /* call instruction for Sun ABI LD sequence */ - R_386_TLS_LDM_POP = 31, /* popl instruction for Sun ABI LD sequence */ - R_386_TLS_LDO_32 = 32, /* 32 bit offset from start of TLS block */ - R_386_TLS_IE_32 = 33, /* 32 bit offset to GOT static TLS offset entry */ - R_386_TLS_LE_32 = 34, /* 32 bit offset within static TLS block */ - R_386_TLS_DTPMOD32 = 35, /* GOT entry containing TLS index */ - R_386_TLS_DTPOFF32 = 36, /* GOT entry containing TLS offset */ - R_386_TLS_TPOFF32 = 37, /* GOT entry of -ve static TLS offset */ - - R_386_COUNT = 38, /* Count of defined relocation types. */ - - R_PPC_NONE = 0, /* No relocation. */ - R_PPC_ADDR32 = 1, - R_PPC_ADDR24 = 2, - R_PPC_ADDR16 = 3, - R_PPC_ADDR16_LO = 4, - R_PPC_ADDR16_HI = 5, - R_PPC_ADDR16_HA = 6, - R_PPC_ADDR14 = 7, - R_PPC_ADDR14_BRTAKEN = 8, - R_PPC_ADDR14_BRNTAKEN = 9, - R_PPC_REL24 = 10, - R_PPC_REL14 = 11, - R_PPC_REL14_BRTAKEN = 12, - R_PPC_REL14_BRNTAKEN = 13, - R_PPC_GOT16 = 14, - R_PPC_GOT16_LO = 15, - R_PPC_GOT16_HI = 16, - R_PPC_GOT16_HA = 17, - R_PPC_PLTREL24 = 18, - R_PPC_COPY = 19, - R_PPC_GLOB_DAT = 20, - R_PPC_JMP_SLOT = 21, - R_PPC_RELATIVE = 22, - R_PPC_LOCAL24PC = 23, - R_PPC_UADDR32 = 24, - R_PPC_UADDR16 = 25, - R_PPC_REL32 = 26, - R_PPC_PLT32 = 27, - R_PPC_PLTREL32 = 28, - R_PPC_PLT16_LO = 29, - R_PPC_PLT16_HI = 30, - R_PPC_PLT16_HA = 31, - R_PPC_SDAREL16 = 32, - R_PPC_SECTOFF = 33, - R_PPC_SECTOFF_LO = 34, - R_PPC_SECTOFF_HI = 35, - R_PPC_SECTOFF_HA = 36, - - R_PPC_COUNT = 37, /* Count of defined relocation types. */ - - R_PPC_TLS = 67, - R_PPC_DTPMOD32 = 68, - R_PPC_TPREL16 = 69, - R_PPC_TPREL16_LO = 70, - R_PPC_TPREL16_HI = 71, - R_PPC_TPREL16_HA = 72, - R_PPC_TPREL32 = 73, - R_PPC_DTPREL16 = 74, - R_PPC_DTPREL16_LO = 75, - R_PPC_DTPREL16_HI = 76, - R_PPC_DTPREL16_HA = 77, - R_PPC_DTPREL32 = 78, - R_PPC_GOT_TLSGD16 = 79, - R_PPC_GOT_TLSGD16_LO = 80, - R_PPC_GOT_TLSGD16_HI = 81, - R_PPC_GOT_TLSGD16_HA = 82, - R_PPC_GOT_TLSLD16 = 83, - R_PPC_GOT_TLSLD16_LO = 84, - R_PPC_GOT_TLSLD16_HI = 85, - R_PPC_GOT_TLSLD16_HA = 86, - R_PPC_GOT_TPREL16 = 87, - R_PPC_GOT_TPREL16_LO = 88, - R_PPC_GOT_TPREL16_HI = 89, - R_PPC_GOT_TPREL16_HA = 90, - - R_PPC_EMB_NADDR32 = 101, - R_PPC_EMB_NADDR16 = 102, - R_PPC_EMB_NADDR16_LO = 103, - R_PPC_EMB_NADDR16_HI = 104, - R_PPC_EMB_NADDR16_HA = 105, - R_PPC_EMB_SDAI16 = 106, - R_PPC_EMB_SDA2I16 = 107, - R_PPC_EMB_SDA2REL = 108, - R_PPC_EMB_SDA21 = 109, - R_PPC_EMB_MRKREF = 110, - R_PPC_EMB_RELSEC16 = 111, - R_PPC_EMB_RELST_LO = 112, - R_PPC_EMB_RELST_HI = 113, - R_PPC_EMB_RELST_HA = 114, - R_PPC_EMB_BIT_FLD = 115, - R_PPC_EMB_RELSDA = 116, - - /* Count of defined relocation types. */ - R_PPC_EMB_COUNT = (R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1), - - R_PPC64_REL24 = R_PPC_REL24, - R_PPC64_JMP_SLOT = R_PPC_JMP_SLOT, - R_PPC64_ADDR64 = 38, - R_PPC64_TOC16 = 47, - R_PPC64_TOC16_LO = 48, - R_PPC64_TOC16_HI = 49, - R_PPC64_TOC16_HA = 50, - R_PPC64_TOC16_DS = 63, - R_PPC64_TOC16_LO_DS = 64, - R_PPC64_REL16_LO = 250, - R_PPC64_REL16_HI = 251, - R_PPC64_REL16_HA = 252, - - R_SPARC_NONE = 0, - R_SPARC_8 = 1, - R_SPARC_16 = 2, - R_SPARC_32 = 3, - R_SPARC_DISP8 = 4, - R_SPARC_DISP16 = 5, - R_SPARC_DISP32 = 6, - R_SPARC_WDISP30 = 7, - R_SPARC_WDISP22 = 8, - R_SPARC_HI22 = 9, - R_SPARC_22 = 10, - R_SPARC_13 = 11, - R_SPARC_LO10 = 12, - R_SPARC_GOT10 = 13, - R_SPARC_GOT13 = 14, - R_SPARC_GOT22 = 15, - R_SPARC_PC10 = 16, - R_SPARC_PC22 = 17, - R_SPARC_WPLT30 = 18, - R_SPARC_COPY = 19, - R_SPARC_GLOB_DAT = 20, - R_SPARC_JMP_SLOT = 21, - R_SPARC_RELATIVE = 22, - R_SPARC_UA32 = 23, - R_SPARC_PLT32 = 24, - R_SPARC_HIPLT22 = 25, - R_SPARC_LOPLT10 = 26, - R_SPARC_PCPLT32 = 27, - R_SPARC_PCPLT22 = 28, - R_SPARC_PCPLT10 = 29, - R_SPARC_10 = 30, - R_SPARC_11 = 31, - R_SPARC_64 = 32, - R_SPARC_OLO10 = 33, - R_SPARC_HH22 = 34, - R_SPARC_HM10 = 35, - R_SPARC_LM22 = 36, - R_SPARC_PC_HH22 = 37, - R_SPARC_PC_HM10 = 38, - R_SPARC_PC_LM22 = 39, - R_SPARC_WDISP16 = 40, - R_SPARC_WDISP19 = 41, - R_SPARC_GLOB_JMP = 42, - R_SPARC_7 = 43, - R_SPARC_5 = 44, - R_SPARC_6 = 45, - R_SPARC_DISP64 = 46, - R_SPARC_PLT64 = 47, - R_SPARC_HIX22 = 48, - R_SPARC_LOX10 = 49, - R_SPARC_H44 = 50, - R_SPARC_M44 = 51, - R_SPARC_L44 = 52, - R_SPARC_REGISTER = 53, - R_SPARC_UA64 = 54, - R_SPARC_UA16 = 55, - - -/* - * Magic number for the elf trampoline, chosen wisely to be an immediate - * value. - */ - ARM_MAGIC_TRAMP_NUMBER = 0x5c000003, -}; - -/* - * Symbol table entries. - */ - -/* For accessing the fields of st_info. */ -uint8 ELF32_ST_BIND(uint8); -uint8 ELF32_ST_TYPE(uint8); - -/* For constructing st_info from field values. */ -uint8 ELF32_ST_INFO(uint8 bind, uint8 type); - -/* For accessing the fields of st_other. */ -uint8 ELF32_ST_VISIBILITY(uint8); - -/* - * ELF header. - */ - -typedef struct ElfEhdr ElfEhdr; -struct ElfEhdr { - uint8 ident[EI_NIDENT]; /* File identification. */ - uint16 type; /* File type. */ - uint16 machine; /* Machine architecture. */ - uint32 version; /* ELF format version. */ - uint64 entry; /* Entry point. */ - uint64 phoff; /* Program header file offset. */ - uint64 shoff; /* Section header file offset. */ - uint32 flags; /* Architecture-specific flags. */ - uint16 ehsize; /* Size of ELF header in bytes. */ - uint16 phentsize; /* Size of program header entry. */ - uint16 phnum; /* Number of program header entries. */ - uint16 shentsize; /* Size of section header entry. */ - uint16 shnum; /* Number of section header entries. */ - uint16 shstrndx; /* Section name strings section. */ -}; - -/* - * Section header. - */ - -typedef struct ElfShdr ElfShdr; -struct ElfShdr { - uint32 name; /* Section name (index into the - section header string table). */ - uint32 type; /* Section type. */ - uint64 flags; /* Section flags. */ - uint64 addr; /* Address in memory image. */ - uint64 off; /* Offset in file. */ - uint64 size; /* Size in bytes. */ - uint32 link; /* Index of a related section. */ - uint32 info; /* Depends on section type. */ - uint64 addralign; /* Alignment in bytes. */ - uint64 entsize; /* Size of each entry in section. */ - - int shnum; /* section number, not stored on disk */ - LSym* secsym; /* section symbol, if needed; not on disk */ -}; - -/* - * Program header. - */ - -typedef struct ElfPhdr ElfPhdr; -struct ElfPhdr { - uint32 type; /* Entry type. */ - uint32 flags; /* Access permission flags. */ - uint64 off; /* File offset of contents. */ - uint64 vaddr; /* Virtual address in memory image. */ - uint64 paddr; /* Physical address (not used). */ - uint64 filesz; /* Size of contents in file. */ - uint64 memsz; /* Size of contents in memory. */ - uint64 align; /* Alignment in memory and file. */ -}; - -/* For accessing the fields of r_info. */ -uint32 ELF64_R_SYM(uint64); -uint32 ELF64_R_TYPE(uint64); - -/* For constructing r_info from field values. */ -uint64 ELF64_R_INFO(uint32, uint32); - -/* - * Symbol table entries. - */ - -/* For accessing the fields of st_info. */ -uint8 ELF64_ST_BIND(uint8); -uint8 ELF64_ST_TYPE(uint8); - -/* For constructing st_info from field values. */ -uint8 ELF64_ST_INFO(uint8 bind, uint8 type); - -/* For accessing the fields of st_other. */ -uint8 ELF64_ST_VISIBILITY(uint8); - -/* - * Go linker interface - */ -enum { - ELF64HDRSIZE = 64, - ELF64PHDRSIZE = 56, - ELF64SHDRSIZE = 64, - ELF64RELSIZE = 16, - ELF64RELASIZE = 24, - ELF64SYMSIZE = 24, - - ELF32HDRSIZE = 52, - ELF32PHDRSIZE = 32, - ELF32SHDRSIZE = 40, - ELF32SYMSIZE = 16, - ELF32RELSIZE = 8, -}; - -/* - * The interface uses the 64-bit structures always, - * to avoid code duplication. The writers know how to - * marshal a 32-bit representation from the 64-bit structure. - */ - -void elfinit(void); -ElfEhdr *getElfEhdr(void); -ElfShdr *newElfShdr(vlong); -ElfPhdr *newElfPhdr(void); -uint32 elfwritehdr(void); -uint32 elfwritephdrs(void); -uint32 elfwriteshdrs(void); -void elfwritedynent(LSym*, int, uint64); -void elfwritedynentsym(LSym*, int, LSym*); -void elfwritedynentsymplus(LSym*, int, LSym*, vlong); -void elfwritedynentsymsize(LSym*, int, LSym*); -uint32 elfhash(uint8*); -uint64 startelf(void); -uint64 endelf(void); -extern int numelfphdr; -extern int numelfshdr; -extern int iself; -extern int elfverneed; -int elfinterp(ElfShdr*, uint64, uint64, char*); -int elfwriteinterp(void); -int elfnetbsdsig(ElfShdr*, uint64, uint64); -int elfwritenetbsdsig(void); -int elfopenbsdsig(ElfShdr*, uint64, uint64); -int elfwriteopenbsdsig(void); -void addbuildinfo(char*); -int elfbuildinfo(ElfShdr*, uint64, uint64); -int elfwritebuildinfo(void); -void elfdynhash(void); -ElfPhdr* elfphload(Segment*); -ElfShdr* elfshbits(Section*); -ElfShdr* elfshalloc(Section*); -ElfShdr* elfshname(char*); -ElfShdr* elfshreloc(Section*); -void elfsetstring(char*, int); -void elfaddverneed(LSym*); -void elfemitreloc(void); -void shsym(ElfShdr*, LSym*); -void phsh(ElfPhdr*, ElfShdr*); -void doelf(void); -void asmbelf(vlong symo); -void asmbelfsetup(void); -void putelfsectionsyms(void); - -EXTERN int elfstrsize; -EXTERN char* elfstrdat; -EXTERN int buildinfolen; - -/* - * Total amount of space to reserve at the start of the file - * for Header, PHeaders, SHeaders, and interp. - * May waste some. - * On FreeBSD, cannot be larger than a page. - */ -enum { - ELFRESERVE = 3072, -}; diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c deleted file mode 100644 index 3432d3b953..0000000000 --- a/src/cmd/ld/go.c +++ /dev/null @@ -1,864 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// go-specific code shared across loaders (5l, 6l, 8l). - -#include -#include -#include -#include -#include "lib.h" - -// accumulate all type information from .6 files. -// check for inconsistencies. - -// TODO: -// generate debugging section in binary. -// once the dust settles, try to move some code to -// libmach, so that other linkers and ar can share. - -/* - * package import data - */ -typedef struct Import Import; -struct Import -{ - Import *hash; // next in hash table - char *prefix; // "type", "var", "func", "const" - char *name; - char *def; - char *file; -}; -enum { - NIHASH = 1024 -}; -static Import *ihash[NIHASH]; -static int nimport; -static void imported(char *pkg, char *import); - -static int -hashstr(char *name) -{ - uint32 h; - char *cp; - - h = 0; - for(cp = name; *cp; h += *cp++) - h *= 1119; - h &= 0xffffff; - return h; -} - -static Import * -ilookup(char *name) -{ - int h; - Import *x; - - h = hashstr(name) % NIHASH; - for(x=ihash[h]; x; x=x->hash) - if(x->name[0] == name[0] && strcmp(x->name, name) == 0) - return x; - x = mal(sizeof *x); - x->name = estrdup(name); - x->hash = ihash[h]; - ihash[h] = x; - nimport++; - return x; -} - -static void loadpkgdata(char*, char*, char*, int); -static void loadcgo(char*, char*, char*, int); -static int parsemethod(char**, char*, char**); -static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**); - -void -ldpkg(Biobuf *f, char *pkg, int64 length, char *filename, int whence) -{ - char *data, *p0, *p1, *name; - - if(debug['g']) - return; - - if((int)length != length) { - fprint(2, "%s: too much pkg data in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - data = mal(length+1); - if(Bread(f, data, length) != length) { - fprint(2, "%s: short pkg read %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - data[length] = '\x00'; - - // first \n$$ marks beginning of exports - skip rest of line - p0 = strstr(data, "\n$$"); - if(p0 == nil) { - if(debug['u'] && whence != ArchiveObj) { - fprint(2, "%s: cannot find export data in %s\n", argv0, filename); - errorexit(); - } - return; - } - p0 += 3; - while(*p0 != '\n' && *p0 != '\x00') - p0++; - - // second marks end of exports / beginning of local data - p1 = strstr(p0, "\n$$"); - if(p1 == nil) { - fprint(2, "%s: cannot find end of exports in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n')) - p0++; - if(p0 < p1) { - if(strncmp(p0, "package ", 8) != 0) { - fprint(2, "%s: bad package section in %s - %s\n", argv0, filename, p0); - if(debug['u']) - errorexit(); - return; - } - p0 += 8; - while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n')) - p0++; - name = p0; - while(p0 < p1 && *p0 != ' ' && *p0 != '\t' && *p0 != '\n') - p0++; - if(debug['u'] && whence != ArchiveObj && - (p0+6 > p1 || memcmp(p0, " safe\n", 6) != 0)) { - fprint(2, "%s: load of unsafe package %s\n", argv0, filename); - nerrors++; - errorexit(); - } - if(p0 < p1) { - if(*p0 == '\n') - *p0++ = '\x00'; - else { - *p0++ = '\x00'; - while(p0 < p1 && *p0 != '\n') - p0++; - } - } - if(strcmp(pkg, "main") == 0 && strcmp(name, "main") != 0) { - fprint(2, "%s: %s: not package main (package %s)\n", argv0, filename, name); - nerrors++; - errorexit(); - } - loadpkgdata(filename, pkg, p0, p1 - p0); - } - - // __.PKGDEF has no cgo section - those are in the C compiler-generated object files. - if(whence == Pkgdef) - return; - - // look for cgo section - p0 = strstr(p1, "\n$$ // cgo"); - if(p0 != nil) { - p0 = strchr(p0+1, '\n'); - if(p0 == nil) { - fprint(2, "%s: found $$ // cgo but no newline in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - p1 = strstr(p0, "\n$$"); - if(p1 == nil) - p1 = strstr(p0, "\n!\n"); - if(p1 == nil) { - fprint(2, "%s: cannot find end of // cgo section in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - loadcgo(filename, pkg, p0 + 1, p1 - (p0+1)); - } -} - -static void -loadpkgdata(char *file, char *pkg, char *data, int length) -{ - char *p, *ep, *prefix, *name, *def; - Import *x; - - file = estrdup(file); - p = data; - ep = data + length; - while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) { - x = ilookup(name); - if(x->prefix == nil) { - x->prefix = prefix; - x->def = estrdup(def); - x->file = file; - } else if(strcmp(x->prefix, prefix) != 0) { - fprint(2, "%s: conflicting definitions for %s\n", argv0, name); - fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name); - fprint(2, "%s:\t%s %s ...\n", file, prefix, name); - nerrors++; - } else if(strcmp(x->def, def) != 0) { - fprint(2, "%s: conflicting definitions for %s\n", argv0, name); - fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def); - fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def); - nerrors++; - } - free(name); - free(def); - } - free(file); -} - -static int -parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp) -{ - char *p, *prefix, *name, *def, *edef, *meth; - int n, inquote; - - // skip white space - p = *pp; -loop: - while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n')) - p++; - if(p == ep || strncmp(p, "$$\n", 3) == 0) - return 0; - - // prefix: (var|type|func|const) - prefix = p; - if(p + 7 > ep) - return -1; - if(strncmp(p, "var ", 4) == 0) - p += 4; - else if(strncmp(p, "type ", 5) == 0) - p += 5; - else if(strncmp(p, "func ", 5) == 0) - p += 5; - else if(strncmp(p, "const ", 6) == 0) - p += 6; - else if(strncmp(p, "import ", 7) == 0) { - p += 7; - while(p < ep && *p != ' ') - p++; - p++; - name = p; - while(p < ep && *p != '\n') - p++; - if(p >= ep) { - fprint(2, "%s: %s: confused in import line\n", argv0, file); - nerrors++; - return -1; - } - *p++ = '\x00'; - imported(pkg, name); - goto loop; - } - else { - fprint(2, "%s: %s: confused in pkg data near <<%.40s>>\n", argv0, file, prefix); - nerrors++; - return -1; - } - p[-1] = '\x00'; - - // name: a.b followed by space - name = p; - inquote = 0; - while(p < ep) { - if (*p == ' ' && !inquote) - break; - - if(*p == '\\') - p++; - else if(*p == '"') - inquote = !inquote; - - p++; - } - - if(p >= ep) - return -1; - *p++ = '\x00'; - - // def: free form to new line - def = p; - while(p < ep && *p != '\n') - p++; - if(p >= ep) - return -1; - edef = p; - *p++ = '\x00'; - - // include methods on successive lines in def of named type - while(parsemethod(&p, ep, &meth) > 0) { - *edef++ = '\n'; // overwrites '\x00' - if(edef+1 > meth) { - // We want to indent methods with a single \t. - // 6g puts at least one char of indent before all method defs, - // so there will be room for the \t. If the method def wasn't - // indented we could do something more complicated, - // but for now just diagnose the problem and assume - // 6g will keep indenting for us. - fprint(2, "%s: %s: expected methods to be indented %p %p %.10s\n", argv0, - file, edef, meth, meth); - nerrors++; - return -1; - } - *edef++ = '\t'; - n = strlen(meth); - memmove(edef, meth, n); - edef += n; - } - - name = expandpkg(name, pkg); - def = expandpkg(def, pkg); - - // done - *pp = p; - *prefixp = prefix; - *namep = name; - *defp = def; - return 1; -} - -static int -parsemethod(char **pp, char *ep, char **methp) -{ - char *p; - - // skip white space - p = *pp; - while(p < ep && (*p == ' ' || *p == '\t')) - p++; - if(p == ep) - return 0; - - // might be a comment about the method - if(p + 2 < ep && strncmp(p, "//", 2) == 0) - goto useline; - - // if it says "func (", it's a method - if(p + 6 < ep && strncmp(p, "func (", 6) == 0) - goto useline; - return 0; - -useline: - // definition to end of line - *methp = p; - while(p < ep && *p != '\n') - p++; - if(p >= ep) { - fprint(2, "%s: lost end of line in method definition\n", argv0); - *pp = ep; - return -1; - } - *p++ = '\x00'; - *pp = p; - return 1; -} - -static void -loadcgo(char *file, char *pkg, char *p, int n) -{ - char *pend, *next, *p0, *q; - char *f[10], *local, *remote, *lib; - int nf; - LSym *s; - - USED(file); - pend = p + n; - p0 = nil; - for(; p 4) - goto err; - - local = f[1]; - remote = local; - if(nf > 2) - remote = f[2]; - lib = ""; - if(nf > 3) - lib = f[3]; - - if(debug['d']) { - fprint(2, "%s: %s: cannot use dynamic imports with -d flag\n", argv0, file); - nerrors++; - return; - } - - if(strcmp(local, "_") == 0 && strcmp(remote, "_") == 0) { - // allow #pragma dynimport _ _ "foo.so" - // to force a link of foo.so. - havedynamic = 1; - thearch.adddynlib(lib); - continue; - } - - local = expandpkg(local, pkg); - q = strchr(remote, '#'); - if(q) - *q++ = '\x00'; - s = linklookup(ctxt, local, 0); - if(local != f[1]) - free(local); - if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) { - s->dynimplib = lib; - s->extname = remote; - s->dynimpvers = q; - if(s->type != SHOSTOBJ) - s->type = SDYNIMPORT; - havedynamic = 1; - } - continue; - } - - if(strcmp(f[0], "cgo_import_static") == 0) { - if(nf != 2) - goto err; - local = f[1]; - s = linklookup(ctxt, local, 0); - s->type = SHOSTOBJ; - s->size = 0; - continue; - } - - if(strcmp(f[0], "cgo_export_static") == 0 || strcmp(f[0], "cgo_export_dynamic") == 0) { - // TODO: Remove once we know Windows is okay. - if(strcmp(f[0], "cgo_export_static") == 0 && HEADTYPE == Hwindows) - continue; - - if(nf < 2 || nf > 3) - goto err; - local = f[1]; - if(nf > 2) - remote = f[2]; - else - remote = local; - local = expandpkg(local, pkg); - s = linklookup(ctxt, local, 0); - - if(flag_shared && s == linklookup(ctxt, "main", 0)) - continue; - - // export overrides import, for openbsd/cgo. - // see issue 4878. - if(s->dynimplib != nil) { - s->dynimplib = nil; - s->extname = nil; - s->dynimpvers = nil; - s->type = 0; - } - - if(s->cgoexport == 0) { - s->extname = remote; - if(ndynexp%32 == 0) - dynexp = erealloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); - dynexp[ndynexp++] = s; - } else if(strcmp(s->extname, remote) != 0) { - fprint(2, "%s: conflicting cgo_export directives: %s as %s and %s\n", argv0, s->name, s->extname, remote); - nerrors++; - return; - } - if(strcmp(f[0], "cgo_export_static") == 0) - s->cgoexport |= CgoExportStatic; - else - s->cgoexport |= CgoExportDynamic; - if(local != f[1]) - free(local); - continue; - } - - if(strcmp(f[0], "cgo_dynamic_linker") == 0) { - if(nf != 2) - goto err; - - if(!debug['I']) { // not overridden by command line - if(interpreter != nil && strcmp(interpreter, f[1]) != 0) { - fprint(2, "%s: conflict dynlinker: %s and %s\n", argv0, interpreter, f[1]); - nerrors++; - return; - } - free(interpreter); - interpreter = estrdup(f[1]); - } - continue; - } - - if(strcmp(f[0], "cgo_ldflag") == 0) { - if(nf != 2) - goto err; - if(nldflag%32 == 0) - ldflag = erealloc(ldflag, (nldflag+32)*sizeof ldflag[0]); - ldflag[nldflag++] = estrdup(f[1]); - continue; - } - } - free(p0); - return; - -err: - fprint(2, "%s: %s: invalid dynimport line: %s\n", argv0, file, p0); - nerrors++; -} - -static LSym *markq; -static LSym *emarkq; - -static void -mark1(LSym *s, LSym *parent) -{ - if(s == nil || s->reachable) - return; - if(strncmp(s->name, "go.weak.", 8) == 0) - return; - s->reachable = 1; - s->reachparent = parent; - if(markq == nil) - markq = s; - else - emarkq->queue = s; - emarkq = s; -} - -void -mark(LSym *s) -{ - mark1(s, nil); -} - -static void -markflood(void) -{ - Auto *a; - LSym *s; - int i; - - for(s=markq; s!=nil; s=s->queue) { - if(s->type == STEXT) { - if(debug['v'] > 1) - Bprint(&bso, "marktext %s\n", s->name); - for(a=s->autom; a; a=a->link) - mark1(a->gotype, s); - } - for(i=0; inr; i++) - mark1(s->r[i].sym, s); - if(s->pcln) { - for(i=0; ipcln->nfuncdata; i++) - mark1(s->pcln->funcdata[i], s); - } - mark1(s->gotype, s); - mark1(s->sub, s); - mark1(s->outer, s); - } -} - -static char* -markextra[] = -{ - "runtime.morestack", - "runtime.morestackx", - - "runtime.morestack00", - "runtime.morestack10", - "runtime.morestack01", - "runtime.morestack11", - - "runtime.morestack8", - "runtime.morestack16", - "runtime.morestack24", - "runtime.morestack32", - "runtime.morestack40", - "runtime.morestack48", - - // on arm, lock in the div/mod helpers too - "_div", - "_divu", - "_mod", - "_modu", -}; - -void -deadcode(void) -{ - int i; - LSym *s, *last, *p; - Fmt fmt; - - if(debug['v']) - Bprint(&bso, "%5.2f deadcode\n", cputime()); - - mark(linklookup(ctxt, INITENTRY, 0)); - for(i=0; iallsym; s != nil; s = s->allsym) { - if(strncmp(s->name, "go.typelink.", 12) == 0) - s->reachable = s->nr==1 && s->r[0].sym->reachable; - } - - // remove dead text but keep file information (z symbols). - last = nil; - for(s = ctxt->textp; s != nil; s = s->next) { - if(!s->reachable) - continue; - // NOTE: Removing s from old textp and adding to new, shorter textp. - if(last == nil) - ctxt->textp = s; - else - last->next = s; - last = s; - } - if(last == nil) - ctxt->textp = nil; - else - last->next = nil; - - for(s = ctxt->allsym; s != nil; s = s->allsym) - if(strncmp(s->name, "go.weak.", 8) == 0) { - s->special = 1; // do not lay out in data segment - s->reachable = 1; - s->hide = 1; - } - - // record field tracking references - fmtstrinit(&fmt); - for(s = ctxt->allsym; s != nil; s = s->allsym) { - if(strncmp(s->name, "go.track.", 9) == 0) { - s->special = 1; // do not lay out in data segment - s->hide = 1; - if(s->reachable) { - fmtprint(&fmt, "%s", s->name+9); - for(p=s->reachparent; p; p=p->reachparent) - fmtprint(&fmt, "\t%s", p->name); - fmtprint(&fmt, "\n"); - } - s->type = SCONST; - s->value = 0; - } - } - if(tracksym == nil) - return; - s = linklookup(ctxt, tracksym, 0); - if(!s->reachable) - return; - addstrdata(tracksym, fmtstrflush(&fmt)); -} - -void -doweak(void) -{ - LSym *s, *t; - - // resolve weak references only if - // target symbol will be in binary anyway. - for(s = ctxt->allsym; s != nil; s = s->allsym) { - if(strncmp(s->name, "go.weak.", 8) == 0) { - t = linkrlookup(ctxt, s->name+8, s->version); - if(t && t->type != 0 && t->reachable) { - s->value = t->value; - s->type = t->type; - s->outer = t; - } else { - s->type = SCONST; - s->value = 0; - } - continue; - } - } -} - -void -addexport(void) -{ - int i; - - if(HEADTYPE == Hdarwin) - return; - - for(i=0; iargs, char*); - if(s == nil) - return fmtstrcpy(fp, ""); - - se = s + strlen(s); - - // NOTE: Keep in sync with ../gc/go.c:/^Zconv. - while(s < se) { - n = chartorune(&r, s); - s += n; - switch(r) { - case Runeerror: - if(n == 1) { - fmtprint(fp, "\\x%02x", (uchar)*(s-1)); - break; - } - // fall through - default: - if(r < ' ') { - fmtprint(fp, "\\x%02x", r); - break; - } - fmtrune(fp, r); - break; - case '\t': - fmtstrcpy(fp, "\\t"); - break; - case '\n': - fmtstrcpy(fp, "\\n"); - break; - case '\"': - case '\\': - fmtrune(fp, '\\'); - fmtrune(fp, r); - break; - case 0xFEFF: // BOM, basically disallowed in source code - fmtstrcpy(fp, "\\uFEFF"); - break; - } - } - return 0; -} - - -typedef struct Pkg Pkg; -struct Pkg -{ - uchar mark; - uchar checked; - Pkg *next; - char *path; - Pkg **impby; - int nimpby; - int mimpby; - Pkg *all; -}; - -static Pkg *phash[1024]; -static Pkg *pkgall; - -static Pkg* -getpkg(char *path) -{ - Pkg *p; - int h; - - h = hashstr(path) % nelem(phash); - for(p=phash[h]; p; p=p->next) - if(strcmp(p->path, path) == 0) - return p; - p = mal(sizeof *p); - p->path = estrdup(path); - p->next = phash[h]; - phash[h] = p; - p->all = pkgall; - pkgall = p; - return p; -} - -static void -imported(char *pkg, char *import) -{ - Pkg *p, *i; - - // everyone imports runtime, even runtime. - if(strcmp(import, "\"runtime\"") == 0) - return; - - pkg = smprint("\"%Z\"", pkg); // turn pkg path into quoted form, freed below - p = getpkg(pkg); - i = getpkg(import); - if(i->nimpby >= i->mimpby) { - i->mimpby *= 2; - if(i->mimpby == 0) - i->mimpby = 16; - i->impby = erealloc(i->impby, i->mimpby*sizeof i->impby[0]); - } - i->impby[i->nimpby++] = p; - free(pkg); -} - -static Pkg* -cycle(Pkg *p) -{ - int i; - Pkg *bad; - - if(p->checked) - return 0; - - if(p->mark) { - nerrors++; - print("import cycle:\n"); - print("\t%s\n", p->path); - return p; - } - p->mark = 1; - for(i=0; inimpby; i++) { - if((bad = cycle(p->impby[i])) != nil) { - p->mark = 0; - p->checked = 1; - print("\timports %s\n", p->path); - if(bad == p) - return nil; - return bad; - } - } - p->checked = 1; - p->mark = 0; - return 0; -} - -void -importcycles(void) -{ - Pkg *p; - - for(p=pkgall; p; p=p->all) - cycle(p); -} - -void -setlinkmode(char *arg) -{ - if(strcmp(arg, "internal") == 0) - linkmode = LinkInternal; - else if(strcmp(arg, "external") == 0) - linkmode = LinkExternal; - else if(strcmp(arg, "auto") == 0) - linkmode = LinkAuto; - else { - fprint(2, "unknown link mode -linkmode %s\n", arg); - errorexit(); - } -} diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c deleted file mode 100644 index f4ddc2c58f..0000000000 --- a/src/cmd/ld/ldelf.c +++ /dev/null @@ -1,958 +0,0 @@ -/* -Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c -http://code.swtch.com/plan9port/src/tip/src/libmach/ - - Copyright © 2004 Russ Cox. - Portions Copyright © 2008-2010 Google Inc. - Portions Copyright © 2010 The Go Authors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include -#include -#include -#include "lib.h" -#include "elf.h" - -enum -{ - ElfClassNone = 0, - ElfClass32, - ElfClass64, - - ElfDataNone = 0, - ElfDataLsb, - ElfDataMsb, - - ElfTypeNone = 0, - ElfTypeRelocatable, - ElfTypeExecutable, - ElfTypeSharedObject, - ElfTypeCore, - /* 0xFF00 - 0xFFFF reserved for processor-specific types */ - - ElfMachNone = 0, - ElfMach32100, /* AT&T WE 32100 */ - ElfMachSparc, /* SPARC */ - ElfMach386, /* Intel 80386 */ - ElfMach68000, /* Motorola 68000 */ - ElfMach88000, /* Motorola 88000 */ - ElfMach486, /* Intel 80486, no longer used */ - ElfMach860, /* Intel 80860 */ - ElfMachMips, /* MIPS RS3000 */ - ElfMachS370, /* IBM System/370 */ - ElfMachMipsLe, /* MIPS RS3000 LE */ - ElfMachParisc = 15, /* HP PA RISC */ - ElfMachVpp500 = 17, /* Fujitsu VPP500 */ - ElfMachSparc32Plus, /* SPARC V8+ */ - ElfMach960, /* Intel 80960 */ - ElfMachPower, /* PowerPC */ - ElfMachPower64, /* PowerPC 64-bit */ - ElfMachS390, /* IBM System/390 */ - ElfMachV800 = 36, /* NEC V800 */ - ElfMachFr20, /* Fujitsu FR20 */ - ElfMachRh32, /* TRW RH-32 */ - ElfMachRce, /* Motorola RCE */ - ElfMachArm, /* ARM */ - ElfMachAlpha, /* Digital Alpha */ - ElfMachSH, /* Hitachi SH */ - ElfMachSparc9, /* SPARC V9 */ - ElfMachAmd64 = 62, - /* and the list goes on... */ - - ElfAbiNone = 0, - ElfAbiSystemV = 0, /* [sic] */ - ElfAbiHPUX, - ElfAbiNetBSD, - ElfAbiLinux, - ElfAbiSolaris = 6, - ElfAbiAix, - ElfAbiIrix, - ElfAbiFreeBSD, - ElfAbiTru64, - ElfAbiModesto, - ElfAbiOpenBSD, - ElfAbiARM = 97, - ElfAbiEmbedded = 255, - - /* some of sections 0xFF00 - 0xFFFF reserved for various things */ - ElfSectNone = 0, - ElfSectProgbits, - ElfSectSymtab, - ElfSectStrtab, - ElfSectRela, - ElfSectHash, - ElfSectDynamic, - ElfSectNote, - ElfSectNobits, - ElfSectRel, - ElfSectShlib, - ElfSectDynsym, - - ElfSectFlagWrite = 0x1, - ElfSectFlagAlloc = 0x2, - ElfSectFlagExec = 0x4, - /* 0xF0000000 are reserved for processor specific */ - - ElfSymBindLocal = 0, - ElfSymBindGlobal, - ElfSymBindWeak, - /* 13-15 reserved */ - - ElfSymTypeNone = 0, - ElfSymTypeObject, - ElfSymTypeFunc, - ElfSymTypeSection, - ElfSymTypeFile, - /* 13-15 reserved */ - - ElfSymShnNone = 0, - ElfSymShnAbs = 0xFFF1, - ElfSymShnCommon = 0xFFF2, - /* 0xFF00-0xFF1F reserved for processors */ - /* 0xFF20-0xFF3F reserved for operating systems */ - - ElfProgNone = 0, - ElfProgLoad, - ElfProgDynamic, - ElfProgInterp, - ElfProgNote, - ElfProgShlib, - ElfProgPhdr, - - ElfProgFlagExec = 0x1, - ElfProgFlagWrite = 0x2, - ElfProgFlagRead = 0x4, - - ElfNotePrStatus = 1, - ElfNotePrFpreg = 2, - ElfNotePrPsinfo = 3, - ElfNotePrTaskstruct = 4, - ElfNotePrAuxv = 6, - ElfNotePrXfpreg = 0x46e62b7f /* for gdb/386 */ -}; - -typedef struct ElfHdrBytes ElfHdrBytes; -typedef struct ElfSectBytes ElfSectBytes; -typedef struct ElfProgBytes ElfProgBytes; -typedef struct ElfSymBytes ElfSymBytes; - -typedef struct ElfHdrBytes64 ElfHdrBytes64; -typedef struct ElfSectBytes64 ElfSectBytes64; -typedef struct ElfProgBytes64 ElfProgBytes64; -typedef struct ElfSymBytes64 ElfSymBytes64; - -struct ElfHdrBytes -{ - uchar ident[16]; - uchar type[2]; - uchar machine[2]; - uchar version[4]; - uchar entry[4]; - uchar phoff[4]; - uchar shoff[4]; - uchar flags[4]; - uchar ehsize[2]; - uchar phentsize[2]; - uchar phnum[2]; - uchar shentsize[2]; - uchar shnum[2]; - uchar shstrndx[2]; -}; - -struct ElfHdrBytes64 -{ - uchar ident[16]; - uchar type[2]; - uchar machine[2]; - uchar version[4]; - uchar entry[8]; - uchar phoff[8]; - uchar shoff[8]; - uchar flags[4]; - uchar ehsize[2]; - uchar phentsize[2]; - uchar phnum[2]; - uchar shentsize[2]; - uchar shnum[2]; - uchar shstrndx[2]; -}; - -struct ElfSectBytes -{ - uchar name[4]; - uchar type[4]; - uchar flags[4]; - uchar addr[4]; - uchar off[4]; - uchar size[4]; - uchar link[4]; - uchar info[4]; - uchar align[4]; - uchar entsize[4]; -}; - -struct ElfSectBytes64 -{ - uchar name[4]; - uchar type[4]; - uchar flags[8]; - uchar addr[8]; - uchar off[8]; - uchar size[8]; - uchar link[4]; - uchar info[4]; - uchar align[8]; - uchar entsize[8]; -}; - -struct ElfSymBytes -{ - uchar name[4]; - uchar value[4]; - uchar size[4]; - uchar info; /* top4: bind, bottom4: type */ - uchar other; - uchar shndx[2]; -}; - -struct ElfSymBytes64 -{ - uchar name[4]; - uchar info; /* top4: bind, bottom4: type */ - uchar other; - uchar shndx[2]; - uchar value[8]; - uchar size[8]; -}; - -typedef struct ElfSect ElfSect; -typedef struct ElfObj ElfObj; -typedef struct ElfSym ElfSym; - -struct ElfSect -{ - char *name; - uint32 nameoff; - uint32 type; - uint64 flags; - uint64 addr; - uint64 off; - uint64 size; - uint32 link; - uint32 info; - uint64 align; - uint64 entsize; - uchar *base; - LSym *sym; -}; - -struct ElfObj -{ - Biobuf *f; - int64 base; // offset in f where ELF begins - int64 length; // length of ELF - int is64; - char *name; - - Endian *e; - ElfSect *sect; - uint nsect; - char *shstrtab; - int nsymtab; - ElfSect *symtab; - ElfSect *symstr; - - uint32 type; - uint32 machine; - uint32 version; - uint64 entry; - uint64 phoff; - uint64 shoff; - uint32 flags; - uint32 ehsize; - uint32 phentsize; - uint32 phnum; - uint32 shentsize; - uint32 shnum; - uint32 shstrndx; -}; - -struct ElfSym -{ - char* name; - uint64 value; - uint64 size; - uchar bind; - uchar type; - uchar other; - uint16 shndx; - LSym* sym; -}; - -uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' }; - -static ElfSect* section(ElfObj*, char*); -static int elfmap(ElfObj*, ElfSect*); -static int readelfsym(ElfObj*, int i, ElfSym*, int); -static int reltype(char*, int, uchar*); - -int -valuecmp(LSym *a, LSym *b) -{ - if(a->value < b->value) - return -1; - if(a->value > b->value) - return +1; - return 0; -} - -void -ldelf(Biobuf *f, char *pkg, int64 length, char *pn) -{ - int32 base; - uint64 add, info; - char *name; - int i, j, rela, is64, n, flag; - uchar hdrbuf[64]; - uchar *p; - ElfHdrBytes *hdr; - ElfObj *elfobj; - ElfSect *sect, *rsect; - ElfSym sym; - Endian *e; - Reloc *r, *rp; - LSym *s; - LSym **symbols; - - symbols = nil; - - if(debug['v']) - Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn); - - ctxt->version++; - base = Boffset(f); - - if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf) - goto bad; - hdr = (ElfHdrBytes*)hdrbuf; - if(memcmp(hdr->ident, ElfMagic, 4) != 0) - goto bad; - switch(hdr->ident[5]) { - case ElfDataLsb: - e = ≤ - break; - case ElfDataMsb: - e = &be; - break; - default: - goto bad; - } - - // read header - elfobj = mal(sizeof *elfobj); - elfobj->e = e; - elfobj->f = f; - elfobj->base = base; - elfobj->length = length; - elfobj->name = pn; - - is64 = 0; - if(hdr->ident[4] == ElfClass64) { - ElfHdrBytes64* hdr; - - is64 = 1; - hdr = (ElfHdrBytes64*)hdrbuf; - elfobj->type = e->e16(hdr->type); - elfobj->machine = e->e16(hdr->machine); - elfobj->version = e->e32(hdr->version); - elfobj->phoff = e->e64(hdr->phoff); - elfobj->shoff = e->e64(hdr->shoff); - elfobj->flags = e->e32(hdr->flags); - elfobj->ehsize = e->e16(hdr->ehsize); - elfobj->phentsize = e->e16(hdr->phentsize); - elfobj->phnum = e->e16(hdr->phnum); - elfobj->shentsize = e->e16(hdr->shentsize); - elfobj->shnum = e->e16(hdr->shnum); - elfobj->shstrndx = e->e16(hdr->shstrndx); - } else { - elfobj->type = e->e16(hdr->type); - elfobj->machine = e->e16(hdr->machine); - elfobj->version = e->e32(hdr->version); - elfobj->entry = e->e32(hdr->entry); - elfobj->phoff = e->e32(hdr->phoff); - elfobj->shoff = e->e32(hdr->shoff); - elfobj->flags = e->e32(hdr->flags); - elfobj->ehsize = e->e16(hdr->ehsize); - elfobj->phentsize = e->e16(hdr->phentsize); - elfobj->phnum = e->e16(hdr->phnum); - elfobj->shentsize = e->e16(hdr->shentsize); - elfobj->shnum = e->e16(hdr->shnum); - elfobj->shstrndx = e->e16(hdr->shstrndx); - } - elfobj->is64 = is64; - - if(hdr->ident[6] != elfobj->version) - goto bad; - - if(e->e16(hdr->type) != ElfTypeRelocatable) { - diag("%s: elf but not elf relocatable object", pn); - return; - } - - switch(thearch.thechar) { - default: - diag("%s: elf %s unimplemented", pn, thestring); - return; - case '5': - if(e != &le || elfobj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) { - diag("%s: elf object but not arm", pn); - return; - } - break; - case '6': - if(e != &le || elfobj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) { - diag("%s: elf object but not amd64", pn); - return; - } - break; - case '8': - if(e != &le || elfobj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) { - diag("%s: elf object but not 386", pn); - return; - } - break; - case '9': - if(elfobj->machine != ElfMachPower64 || hdr->ident[4] != ElfClass64) { - diag("%s: elf object but not ppc64", pn); - return; - } - break; - } - - // load section list into memory. - elfobj->sect = mal(elfobj->shnum*sizeof elfobj->sect[0]); - elfobj->nsect = elfobj->shnum; - for(i=0; insect; i++) { - if(Bseek(f, base+elfobj->shoff+i*elfobj->shentsize, 0) < 0) - goto bad; - sect = &elfobj->sect[i]; - if(is64) { - ElfSectBytes64 b; - - werrstr("short read"); - if(Bread(f, &b, sizeof b) != sizeof b) - goto bad; - - sect->nameoff = (uintptr)e->e32(b.name); - sect->type = e->e32(b.type); - sect->flags = e->e64(b.flags); - sect->addr = e->e64(b.addr); - sect->off = e->e64(b.off); - sect->size = e->e64(b.size); - sect->link = e->e32(b.link); - sect->info = e->e32(b.info); - sect->align = e->e64(b.align); - sect->entsize = e->e64(b.entsize); - } else { - ElfSectBytes b; - - werrstr("short read"); - if(Bread(f, &b, sizeof b) != sizeof b) - goto bad; - - sect->nameoff = (uintptr)e->e32(b.name); - sect->type = e->e32(b.type); - sect->flags = e->e32(b.flags); - sect->addr = e->e32(b.addr); - sect->off = e->e32(b.off); - sect->size = e->e32(b.size); - sect->link = e->e32(b.link); - sect->info = e->e32(b.info); - sect->align = e->e32(b.align); - sect->entsize = e->e32(b.entsize); - } - } - - // read section string table and translate names - if(elfobj->shstrndx >= elfobj->nsect) { - werrstr("shstrndx out of range %d >= %d", elfobj->shstrndx, elfobj->nsect); - goto bad; - } - sect = &elfobj->sect[elfobj->shstrndx]; - if(elfmap(elfobj, sect) < 0) - goto bad; - for(i=0; insect; i++) - if(elfobj->sect[i].nameoff != 0) - elfobj->sect[i].name = (char*)sect->base + elfobj->sect[i].nameoff; - - // load string table for symbols into memory. - elfobj->symtab = section(elfobj, ".symtab"); - if(elfobj->symtab == nil) { - // our work is done here - no symbols means nothing can refer to this file - return; - } - if(elfobj->symtab->link <= 0 || elfobj->symtab->link >= elfobj->nsect) { - diag("%s: elf object has symbol table with invalid string table link", pn); - return; - } - elfobj->symstr = &elfobj->sect[elfobj->symtab->link]; - if(is64) - elfobj->nsymtab = elfobj->symtab->size / sizeof(ElfSymBytes64); - else - elfobj->nsymtab = elfobj->symtab->size / sizeof(ElfSymBytes); - - if(elfmap(elfobj, elfobj->symtab) < 0) - goto bad; - if(elfmap(elfobj, elfobj->symstr) < 0) - goto bad; - - // load text and data segments into memory. - // they are not as small as the section lists, but we'll need - // the memory anyway for the symbol images, so we might - // as well use one large chunk. - - // create symbols for elfmapped sections - for(i=0; insect; i++) { - sect = &elfobj->sect[i]; - if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc)) - continue; - if(sect->type != ElfSectNobits && elfmap(elfobj, sect) < 0) - goto bad; - - name = smprint("%s(%s)", pkg, sect->name); - s = linklookup(ctxt, name, ctxt->version); - free(name); - switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) { - default: - werrstr("unexpected flags for ELF section %s", sect->name); - goto bad; - case ElfSectFlagAlloc: - s->type = SRODATA; - break; - case ElfSectFlagAlloc + ElfSectFlagWrite: - if(sect->type == ElfSectNobits) - s->type = SNOPTRBSS; - else - s->type = SNOPTRDATA; - break; - case ElfSectFlagAlloc + ElfSectFlagExec: - s->type = STEXT; - break; - } - if(strcmp(sect->name, ".got") == 0 || - strcmp(sect->name, ".toc") == 0) - s->type = SELFGOT; - if(sect->type == ElfSectProgbits) { - s->p = sect->base; - s->np = sect->size; - } - s->size = sect->size; - s->align = sect->align; - sect->sym = s; - } - - // enter sub-symbols into symbol table. - // symbol 0 is the null symbol. - symbols = malloc(elfobj->nsymtab * sizeof(symbols[0])); - if(symbols == nil) { - diag("out of memory"); - errorexit(); - } - for(i=1; insymtab; i++) { - if(readelfsym(elfobj, i, &sym, 1) < 0) - goto bad; - symbols[i] = sym.sym; - if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone) - continue; - if(sym.shndx == ElfSymShnCommon) { - s = sym.sym; - if(s->size < sym.size) - s->size = sym.size; - if(s->type == 0 || s->type == SXREF) - s->type = SNOPTRBSS; - continue; - } - if(sym.shndx >= elfobj->nsect || sym.shndx == 0) - continue; - // even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols - if(sym.sym == nil) - continue; - sect = elfobj->sect+sym.shndx; - if(sect->sym == nil) { - if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this - continue; - diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type); - continue; - } - s = sym.sym; - if(s->outer != nil) { - if(s->dupok) - continue; - diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); - errorexit(); - } - s->sub = sect->sym->sub; - sect->sym->sub = s; - s->type = sect->sym->type | (s->type&~SMASK) | SSUB; - if(!(s->cgoexport & CgoExportDynamic)) - s->dynimplib = nil; // satisfy dynimport - s->value = sym.value; - s->size = sym.size; - s->outer = sect->sym; - if(sect->sym->type == STEXT) { - if(s->external && !s->dupok) - diag("%s: duplicate definition of %s", pn, s->name); - s->external = 1; - } - if(elfobj->machine == ElfMachPower64) { - flag = sym.other >> 5; - if(2 <= flag && flag <= 6) - s->localentry = 1 << (flag - 2); - else if(flag == 7) - diag("%s: invalid sym.other 0x%x for %s", pn, sym.other, s->name); - } - } - - // Sort outer lists by address, adding to textp. - // This keeps textp in increasing address order. - for(i=0; insect; i++) { - s = elfobj->sect[i].sym; - if(s == nil) - continue; - if(s->sub) - s->sub = listsort(s->sub, valuecmp, listsubp); - if(s->type == STEXT) { - if(s->onlist) - sysfatal("symbol %s listed multiple times", s->name); - s->onlist = 1; - if(ctxt->etextp) - ctxt->etextp->next = s; - else - ctxt->textp = s; - ctxt->etextp = s; - for(s = s->sub; s != nil; s = s->sub) { - if(s->onlist) - sysfatal("symbol %s listed multiple times", s->name); - s->onlist = 1; - ctxt->etextp->next = s; - ctxt->etextp = s; - } - } - } - - // load relocations - for(i=0; insect; i++) { - rsect = &elfobj->sect[i]; - if(rsect->type != ElfSectRela && rsect->type != ElfSectRel) - continue; - if(rsect->info >= elfobj->nsect || elfobj->sect[rsect->info].base == nil) - continue; - sect = &elfobj->sect[rsect->info]; - if(elfmap(elfobj, rsect) < 0) - goto bad; - rela = rsect->type == ElfSectRela; - n = rsect->size/(4+4*is64)/(2+rela); - r = mal(n*sizeof r[0]); - p = rsect->base; - for(j=0; joff = e->e64(p); - p += 8; - info = e->e64(p); - p += 8; - if(rela) { - add = e->e64(p); - p += 8; - } - } else { - // 32-bit rel/rela - rp->off = e->e32(p); - p += 4; - info = e->e32(p); - info = info>>8<<32 | (info&0xff); // convert to 64-bit info - p += 4; - if(rela) { - add = e->e32(p); - p += 4; - } - } - if((info & 0xffffffff) == 0) { // skip R_*_NONE relocation - j--; - n--; - continue; - } - if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol - rp->sym = nil; - } else { - if(readelfsym(elfobj, info>>32, &sym, 0) < 0) - goto bad; - sym.sym = symbols[info>>32]; - if(sym.sym == nil) { - werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", - sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type); - goto bad; - } - rp->sym = sym.sym; - } - rp->type = reltype(pn, (uint32)info, &rp->siz); - if(rela) - rp->add = add; - else { - // load addend from image - if(rp->siz == 4) - rp->add = e->e32(sect->base+rp->off); - else if(rp->siz == 8) - rp->add = e->e64(sect->base+rp->off); - else - diag("invalid rela size %d", rp->siz); - } - if(rp->siz == 2) - rp->add = (int16)rp->add; - if(rp->siz == 4) - rp->add = (int32)rp->add; - //print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add); - } - qsort(r, n, sizeof r[0], rbyoff); // just in case - - s = sect->sym; - s->r = r; - s->nr = n; - } - free(symbols); - - return; - -bad: - diag("%s: malformed elf file: %r", pn); - free(symbols); -} - -static ElfSect* -section(ElfObj *elfobj, char *name) -{ - int i; - - for(i=0; insect; i++) - if(elfobj->sect[i].name && name && strcmp(elfobj->sect[i].name, name) == 0) - return &elfobj->sect[i]; - return nil; -} - -static int -elfmap(ElfObj *elfobj, ElfSect *sect) -{ - if(sect->base != nil) - return 0; - - if(sect->off+sect->size > elfobj->length) { - werrstr("elf section past end of file"); - return -1; - } - - sect->base = mal(sect->size); - werrstr("short read"); - if(Bseek(elfobj->f, elfobj->base+sect->off, 0) < 0 || Bread(elfobj->f, sect->base, sect->size) != sect->size) - return -1; - - return 0; -} - -static int -readelfsym(ElfObj *elfobj, int i, ElfSym *sym, int needSym) -{ - LSym *s; - - if(i >= elfobj->nsymtab || i < 0) { - werrstr("invalid elf symbol index"); - return -1; - } - if(i == 0) { - diag("readym: read null symbol!"); - } - - if(elfobj->is64) { - ElfSymBytes64 *b; - - b = (ElfSymBytes64*)(elfobj->symtab->base + i*sizeof *b); - sym->name = (char*)elfobj->symstr->base + elfobj->e->e32(b->name); - sym->value = elfobj->e->e64(b->value); - sym->size = elfobj->e->e64(b->size); - sym->shndx = elfobj->e->e16(b->shndx); - sym->bind = b->info>>4; - sym->type = b->info&0xf; - sym->other = b->other; - } else { - ElfSymBytes *b; - - b = (ElfSymBytes*)(elfobj->symtab->base + i*sizeof *b); - sym->name = (char*)elfobj->symstr->base + elfobj->e->e32(b->name); - sym->value = elfobj->e->e32(b->value); - sym->size = elfobj->e->e32(b->size); - sym->shndx = elfobj->e->e16(b->shndx); - sym->bind = b->info>>4; - sym->type = b->info&0xf; - sym->other = b->other; - } - - s = nil; - if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0) - sym->name = ".got"; - if(strcmp(sym->name, ".TOC.") == 0) - // Magic symbol on ppc64. Will be set to this object - // file's .got+0x8000. - sym->bind = ElfSymBindLocal; - switch(sym->type) { - case ElfSymTypeSection: - s = elfobj->sect[sym->shndx].sym; - break; - case ElfSymTypeObject: - case ElfSymTypeFunc: - case ElfSymTypeNone: - switch(sym->bind) { - case ElfSymBindGlobal: - if(needSym) { - s = linklookup(ctxt, sym->name, 0); - // for global scoped hidden symbols we should insert it into - // symbol hash table, but mark them as hidden. - // __i686.get_pc_thunk.bx is allowed to be duplicated, to - // workaround that we set dupok. - // TODO(minux): correctly handle __i686.get_pc_thunk.bx without - // set dupok generally. See http://codereview.appspot.com/5823055/ - // comment #5 for details. - if(s && sym->other == 2) { - s->type |= SHIDDEN; - s->dupok = 1; - } - } - break; - case ElfSymBindLocal: - if(thearch.thechar == '5' && (strncmp(sym->name, "$a", 2) == 0 || strncmp(sym->name, "$d", 2) == 0)) { - // binutils for arm generate these elfmapping - // symbols, ignore these - break; - } - if(strcmp(sym->name, ".TOC.") == 0) { - // We need to be able to look this up, - // so put it in the hash table. - if(needSym) { - s = linklookup(ctxt, sym->name, ctxt->version); - s->type |= SHIDDEN; - } - break; - } - if(needSym) { - // local names and hidden visiblity global names are unique - // and should only reference by its index, not name, so we - // don't bother to add them into hash table - s = linknewsym(ctxt, sym->name, ctxt->version); - s->type |= SHIDDEN; - } - break; - case ElfSymBindWeak: - if(needSym) { - s = linknewsym(ctxt, sym->name, 0); - if(sym->other == 2) - s->type |= SHIDDEN; - } - break; - default: - werrstr("%s: invalid symbol binding %d", sym->name, sym->bind); - return -1; - } - break; - } - if(s != nil && s->type == 0 && sym->type != ElfSymTypeSection) - s->type = SXREF; - sym->sym = s; - - return 0; -} - -int -rbyoff(const void *va, const void *vb) -{ - Reloc *a, *b; - - a = (Reloc*)va; - b = (Reloc*)vb; - if(a->off < b->off) - return -1; - if(a->off > b->off) - return +1; - return 0; -} - -#define R(x, y) ((x)|((y)<<24)) -/*c2go uint32 R(uint32, uint32); */ - -static int -reltype(char *pn, int elftype, uchar *siz) -{ - switch(R(thearch.thechar, elftype)) { - default: - diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype); - case R('9', R_PPC64_TOC16): - case R('9', R_PPC64_TOC16_LO): - case R('9', R_PPC64_TOC16_HI): - case R('9', R_PPC64_TOC16_HA): - case R('9', R_PPC64_TOC16_DS): - case R('9', R_PPC64_TOC16_LO_DS): - case R('9', R_PPC64_REL16_LO): - case R('9', R_PPC64_REL16_HI): - case R('9', R_PPC64_REL16_HA): - *siz = 2; - break; - case R('5', R_ARM_ABS32): - case R('5', R_ARM_GOT32): - case R('5', R_ARM_PLT32): - case R('5', R_ARM_GOTOFF): - case R('5', R_ARM_GOTPC): - case R('5', R_ARM_THM_PC22): - case R('5', R_ARM_REL32): - case R('5', R_ARM_CALL): - case R('5', R_ARM_V4BX): - case R('5', R_ARM_GOT_PREL): - case R('5', R_ARM_PC24): - case R('5', R_ARM_JUMP24): - case R('6', R_X86_64_PC32): - case R('6', R_X86_64_PLT32): - case R('6', R_X86_64_GOTPCREL): - case R('8', R_386_32): - case R('8', R_386_PC32): - case R('8', R_386_GOT32): - case R('8', R_386_PLT32): - case R('8', R_386_GOTOFF): - case R('8', R_386_GOTPC): - case R('9', R_PPC64_REL24): - *siz = 4; - break; - case R('6', R_X86_64_64): - case R('9', R_PPC64_ADDR64): - *siz = 8; - break; - } - - return 256+elftype; -} diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c deleted file mode 100644 index 300f18a2eb..0000000000 --- a/src/cmd/ld/ldmacho.c +++ /dev/null @@ -1,853 +0,0 @@ -/* -Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c -http://code.swtch.com/plan9port/src/tip/src/libmach/ - - Copyright © 2004 Russ Cox. - Portions Copyright © 2008-2010 Google Inc. - Portions Copyright © 2010 The Go Authors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include -#include -#include -#include -#include "lib.h" -#include "macho.h" - -enum { - N_EXT = 0x01, - N_TYPE = 0x1e, - N_STAB = 0xe0, -}; - -typedef struct LdMachoObj LdMachoObj; -typedef struct LdMachoCmd LdMachoCmd; -typedef struct LdMachoSeg LdMachoSeg; -typedef struct LdMachoSect LdMachoSect; -typedef struct LdMachoRel LdMachoRel; -typedef struct LdMachoSymtab LdMachoSymtab; -typedef struct LdMachoSym LdMachoSym; -typedef struct LdMachoDysymtab LdMachoDysymtab; - -enum -{ - LdMachoCpuVax = 1, - LdMachoCpu68000 = 6, - LdMachoCpu386 = 7, - LdMachoCpuAmd64 = 0x1000007, - LdMachoCpuMips = 8, - LdMachoCpu98000 = 10, - LdMachoCpuHppa = 11, - LdMachoCpuArm = 12, - LdMachoCpu88000 = 13, - LdMachoCpuSparc = 14, - LdMachoCpu860 = 15, - LdMachoCpuAlpha = 16, - LdMachoCpuPower = 18, - - LdMachoCmdSegment = 1, - LdMachoCmdSymtab = 2, - LdMachoCmdSymseg = 3, - LdMachoCmdThread = 4, - LdMachoCmdDysymtab = 11, - LdMachoCmdSegment64 = 25, - - LdMachoFileObject = 1, - LdMachoFileExecutable = 2, - LdMachoFileFvmlib = 3, - LdMachoFileCore = 4, - LdMachoFilePreload = 5, -}; - -struct LdMachoSeg -{ - char name[16+1]; - uint64 vmaddr; - uint64 vmsize; - uint32 fileoff; - uint32 filesz; - uint32 maxprot; - uint32 initprot; - uint32 nsect; - uint32 flags; - LdMachoSect *sect; -}; - -struct LdMachoSect -{ - char name[16+1]; - char segname[16+1]; - uint64 addr; - uint64 size; - uint32 off; - uint32 align; - uint32 reloff; - uint32 nreloc; - uint32 flags; - uint32 res1; - uint32 res2; - LSym *sym; - - LdMachoRel *rel; -}; - -struct LdMachoRel -{ - uint32 addr; - uint32 symnum; - uint8 pcrel; - uint8 length; - uint8 extrn; - uint8 type; - uint8 scattered; - uint32 value; -}; - -struct LdMachoSymtab -{ - uint32 symoff; - uint32 nsym; - uint32 stroff; - uint32 strsize; - - char *str; - LdMachoSym *sym; -}; - -struct LdMachoSym -{ - char *name; - uint8 type; - uint8 sectnum; - uint16 desc; - char kind; - uint64 value; - LSym *sym; -}; - -struct LdMachoDysymtab -{ - uint32 ilocalsym; - uint32 nlocalsym; - uint32 iextdefsym; - uint32 nextdefsym; - uint32 iundefsym; - uint32 nundefsym; - uint32 tocoff; - uint32 ntoc; - uint32 modtaboff; - uint32 nmodtab; - uint32 extrefsymoff; - uint32 nextrefsyms; - uint32 indirectsymoff; - uint32 nindirectsyms; - uint32 extreloff; - uint32 nextrel; - uint32 locreloff; - uint32 nlocrel; - uint32 *indir; -}; - -struct LdMachoCmd -{ - int type; - uint32 off; - uint32 size; - LdMachoSeg seg; - LdMachoSymtab sym; - LdMachoDysymtab dsym; -}; - -struct LdMachoObj -{ - Biobuf *f; - int64 base; // off in f where Mach-O begins - int64 length; // length of Mach-O - int is64; - char *name; - - Endian *e; - uint cputype; - uint subcputype; - uint32 filetype; - uint32 flags; - LdMachoCmd *cmd; - uint ncmd; -}; - -static int -unpackcmd(uchar *p, LdMachoObj *m, LdMachoCmd *c, uint type, uint sz) -{ - uint32 (*e4)(uchar*); - uint64 (*e8)(uchar*); - LdMachoSect *s; - int i; - - e4 = m->e->e32; - e8 = m->e->e64; - - c->type = type; - c->size = sz; - switch(type){ - default: - return -1; - case LdMachoCmdSegment: - if(sz < 56) - return -1; - strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8); - c->seg.vmaddr = e4(p+24); - c->seg.vmsize = e4(p+28); - c->seg.fileoff = e4(p+32); - c->seg.filesz = e4(p+36); - c->seg.maxprot = e4(p+40); - c->seg.initprot = e4(p+44); - c->seg.nsect = e4(p+48); - c->seg.flags = e4(p+52); - c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]); - if(sz < 56+c->seg.nsect*68) - return -1; - p += 56; - for(i=0; iseg.nsect; i++) { - s = &c->seg.sect[i]; - strecpy(s->name, s->name+sizeof s->name, (char*)p+0); - strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16); - s->addr = e4(p+32); - s->size = e4(p+36); - s->off = e4(p+40); - s->align = e4(p+44); - s->reloff = e4(p+48); - s->nreloc = e4(p+52); - s->flags = e4(p+56); - s->res1 = e4(p+60); - s->res2 = e4(p+64); - p += 68; - } - break; - case LdMachoCmdSegment64: - if(sz < 72) - return -1; - strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8); - c->seg.vmaddr = e8(p+24); - c->seg.vmsize = e8(p+32); - c->seg.fileoff = e8(p+40); - c->seg.filesz = e8(p+48); - c->seg.maxprot = e4(p+56); - c->seg.initprot = e4(p+60); - c->seg.nsect = e4(p+64); - c->seg.flags = e4(p+68); - c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]); - if(sz < 72+c->seg.nsect*80) - return -1; - p += 72; - for(i=0; iseg.nsect; i++) { - s = &c->seg.sect[i]; - strecpy(s->name, s->name+sizeof s->name, (char*)p+0); - strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16); - s->addr = e8(p+32); - s->size = e8(p+40); - s->off = e4(p+48); - s->align = e4(p+52); - s->reloff = e4(p+56); - s->nreloc = e4(p+60); - s->flags = e4(p+64); - s->res1 = e4(p+68); - s->res2 = e4(p+72); - // p+76 is reserved - p += 80; - } - break; - case LdMachoCmdSymtab: - if(sz < 24) - return -1; - c->sym.symoff = e4(p+8); - c->sym.nsym = e4(p+12); - c->sym.stroff = e4(p+16); - c->sym.strsize = e4(p+20); - break; - case LdMachoCmdDysymtab: - if(sz < 80) - return -1; - c->dsym.ilocalsym = e4(p+8); - c->dsym.nlocalsym = e4(p+12); - c->dsym.iextdefsym = e4(p+16); - c->dsym.nextdefsym = e4(p+20); - c->dsym.iundefsym = e4(p+24); - c->dsym.nundefsym = e4(p+28); - c->dsym.tocoff = e4(p+32); - c->dsym.ntoc = e4(p+36); - c->dsym.modtaboff = e4(p+40); - c->dsym.nmodtab = e4(p+44); - c->dsym.extrefsymoff = e4(p+48); - c->dsym.nextrefsyms = e4(p+52); - c->dsym.indirectsymoff = e4(p+56); - c->dsym.nindirectsyms = e4(p+60); - c->dsym.extreloff = e4(p+64); - c->dsym.nextrel = e4(p+68); - c->dsym.locreloff = e4(p+72); - c->dsym.nlocrel = e4(p+76); - break; - } - return 0; -} - -static int -macholoadrel(LdMachoObj *m, LdMachoSect *sect) -{ - LdMachoRel *rel, *r; - uchar *buf, *p; - int i, n; - uint32 v; - - if(sect->rel != nil || sect->nreloc == 0) - return 0; - rel = mal(sect->nreloc * sizeof r[0]); - n = sect->nreloc * 8; - buf = mal(n); - if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n) - return -1; - for(i=0; inreloc; i++) { - r = &rel[i]; - p = buf+i*8; - r->addr = m->e->e32(p); - - // TODO(rsc): Wrong interpretation for big-endian bitfields? - if(r->addr & 0x80000000) { - // scatterbrained relocation - r->scattered = 1; - v = r->addr >> 24; - r->addr &= 0xFFFFFF; - r->type = v & 0xF; - v >>= 4; - r->length = 1<<(v&3); - v >>= 2; - r->pcrel = v & 1; - r->value = m->e->e32(p+4); - } else { - v = m->e->e32(p+4); - r->symnum = v & 0xFFFFFF; - v >>= 24; - r->pcrel = v&1; - v >>= 1; - r->length = 1<<(v&3); - v >>= 2; - r->extrn = v&1; - v >>= 1; - r->type = v; - } - } - sect->rel = rel; - return 0; -} - -static int -macholoaddsym(LdMachoObj *m, LdMachoDysymtab *d) -{ - uchar *p; - int i, n; - - n = d->nindirectsyms; - - p = mal(n*4); - if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4) - return -1; - - d->indir = (uint32*)p; - for(i=0; iindir[i] = m->e->e32(p+4*i); - return 0; -} - -static int -macholoadsym(LdMachoObj *m, LdMachoSymtab *symtab) -{ - char *strbuf; - uchar *symbuf, *p; - int i, n, symsize; - LdMachoSym *sym, *s; - uint32 v; - - if(symtab->sym != nil) - return 0; - - strbuf = mal(symtab->strsize); - if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize) - return -1; - - symsize = 12; - if(m->is64) - symsize = 16; - n = symtab->nsym * symsize; - symbuf = mal(n); - if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n) - return -1; - sym = mal(symtab->nsym * sizeof sym[0]); - p = symbuf; - for(i=0; insym; i++) { - s = &sym[i]; - v = m->e->e32(p); - if(v >= symtab->strsize) - return -1; - s->name = strbuf + v; - s->type = p[4]; - s->sectnum = p[5]; - s->desc = m->e->e16(p+6); - if(m->is64) - s->value = m->e->e64(p+8); - else - s->value = m->e->e32(p+8); - p += symsize; - } - symtab->str = strbuf; - symtab->sym = sym; - return 0; -} - -void -ldmacho(Biobuf *f, char *pkg, int64 length, char *pn) -{ - int i, j, is64; - uint64 secaddr; - uchar hdr[7*4], *cmdp; - uchar tmp[4]; - uchar *dat; - ulong ncmd, cmdsz, ty, sz, off; - LdMachoObj *m; - Endian *e; - int64 base; - LdMachoSect *sect; - LdMachoRel *rel; - int rpi; - LSym *s, *s1, *outer; - LdMachoCmd *c; - LdMachoSymtab *symtab; - LdMachoDysymtab *dsymtab; - LdMachoSym *sym; - Reloc *r, *rp; - char *name; - - ctxt->version++; - base = Boffset(f); - if(Bread(f, hdr, sizeof hdr) != sizeof hdr) - goto bad; - - if((be.e32(hdr)&~1) == 0xFEEDFACE){ - e = &be; - }else if((le.e32(hdr)&~1) == 0xFEEDFACE){ - e = ≤ - }else{ - werrstr("bad magic - not mach-o file"); - goto bad; - } - - is64 = e->e32(hdr) == 0xFEEDFACF; - ncmd = e->e32(hdr+4*4); - cmdsz = e->e32(hdr+5*4); - if(ncmd > 0x10000 || cmdsz >= 0x01000000){ - werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz); - goto bad; - } - if(is64) - Bread(f, tmp, 4); // skip reserved word in header - - m = mal(sizeof(*m)+ncmd*sizeof(LdMachoCmd)+cmdsz); - m->f = f; - m->e = e; - m->cputype = e->e32(hdr+1*4); - m->subcputype = e->e32(hdr+2*4); - m->filetype = e->e32(hdr+3*4); - m->ncmd = ncmd; - m->flags = e->e32(hdr+6*4); - m->is64 = is64; - m->base = base; - m->length = length; - m->name = pn; - - switch(thearch.thechar) { - default: - diag("%s: mach-o %s unimplemented", pn, thestring); - return; - case '6': - if(e != &le || m->cputype != LdMachoCpuAmd64) { - diag("%s: mach-o object but not amd64", pn); - return; - } - break; - case '8': - if(e != &le || m->cputype != LdMachoCpu386) { - diag("%s: mach-o object but not 386", pn); - return; - } - break; - } - - m->cmd = (LdMachoCmd*)(m+1); - off = sizeof hdr; - cmdp = (uchar*)(m->cmd+ncmd); - if(Bread(f, cmdp, cmdsz) != cmdsz){ - werrstr("reading cmds: %r"); - goto bad; - } - - // read and parse load commands - c = nil; - symtab = nil; - dsymtab = nil; - USED(dsymtab); - for(i=0; ie32(cmdp); - sz = e->e32(cmdp+4); - m->cmd[i].off = off; - unpackcmd(cmdp, m, &m->cmd[i], ty, sz); - cmdp += sz; - off += sz; - if(ty == LdMachoCmdSymtab) { - if(symtab != nil) { - werrstr("multiple symbol tables"); - goto bad; - } - symtab = &m->cmd[i].sym; - macholoadsym(m, symtab); - } - if(ty == LdMachoCmdDysymtab) { - dsymtab = &m->cmd[i].dsym; - macholoaddsym(m, dsymtab); - } - if((is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment)) { - if(c != nil) { - werrstr("multiple load commands"); - goto bad; - } - c = &m->cmd[i]; - } - } - - // load text and data segments into memory. - // they are not as small as the load commands, but we'll need - // the memory anyway for the symbol images, so we might - // as well use one large chunk. - if(c == nil) { - werrstr("no load command"); - goto bad; - } - if(symtab == nil) { - // our work is done here - no symbols means nothing can refer to this file - return; - } - - if(c->seg.fileoff+c->seg.filesz >= length) { - werrstr("load segment out of range"); - goto bad; - } - - dat = mal(c->seg.filesz); - if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) { - werrstr("cannot load object data: %r"); - goto bad; - } - - for(i=0; iseg.nsect; i++) { - sect = &c->seg.sect[i]; - if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0) - continue; - if(strcmp(sect->name, "__eh_frame") == 0) - continue; - name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name); - s = linklookup(ctxt, name, ctxt->version); - if(s->type != 0) { - werrstr("duplicate %s/%s", sect->segname, sect->name); - goto bad; - } - free(name); - - s->np = sect->size; - s->size = s->np; - if((sect->flags & 0xff) == 1) // S_ZEROFILL - s->p = mal(s->size); - else { - s->p = dat + sect->addr - c->seg.vmaddr; - } - - if(strcmp(sect->segname, "__TEXT") == 0) { - if(strcmp(sect->name, "__text") == 0) - s->type = STEXT; - else - s->type = SRODATA; - } else { - if (strcmp(sect->name, "__bss") == 0) { - s->type = SNOPTRBSS; - s->np = 0; - } else - s->type = SNOPTRDATA; - } - sect->sym = s; - } - - // enter sub-symbols into symbol table. - // have to guess sizes from next symbol. - for(i=0; insym; i++) { - int v; - sym = &symtab->sym[i]; - if(sym->type&N_STAB) - continue; - // TODO: check sym->type against outer->type. - name = sym->name; - if(name[0] == '_' && name[1] != '\x00') - name++; - v = 0; - if(!(sym->type&N_EXT)) - v = ctxt->version; - s = linklookup(ctxt, name, v); - if(!(sym->type&N_EXT)) - s->dupok = 1; - sym->sym = s; - if(sym->sectnum == 0) // undefined - continue; - if(sym->sectnum > c->seg.nsect) { - werrstr("reference to invalid section %d", sym->sectnum); - goto bad; - } - sect = &c->seg.sect[sym->sectnum-1]; - outer = sect->sym; - if(outer == nil) { - werrstr("reference to invalid section %s/%s", sect->segname, sect->name); - continue; - } - if(s->outer != nil) { - if(s->dupok) - continue; - diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); - errorexit(); - } - s->type = outer->type | SSUB; - s->sub = outer->sub; - outer->sub = s; - s->outer = outer; - s->value = sym->value - sect->addr; - if(!(s->cgoexport & CgoExportDynamic)) - s->dynimplib = nil; // satisfy dynimport - if(outer->type == STEXT) { - if(s->external && !s->dupok) - diag("%s: duplicate definition of %s", pn, s->name); - s->external = 1; - } - sym->sym = s; - } - - // Sort outer lists by address, adding to textp. - // This keeps textp in increasing address order. - for(i=0; iseg.nsect; i++) { - sect = &c->seg.sect[i]; - if((s = sect->sym) == nil) - continue; - if(s->sub) { - s->sub = listsort(s->sub, valuecmp, listsubp); - - // assign sizes, now that we know symbols in sorted order. - for(s1 = s->sub; s1 != nil; s1 = s1->sub) { - if(s1->sub) - s1->size = s1->sub->value - s1->value; - else - s1->size = s->value + s->size - s1->value; - } - } - if(s->type == STEXT) { - if(s->onlist) - sysfatal("symbol %s listed multiple times", s->name); - s->onlist = 1; - if(ctxt->etextp) - ctxt->etextp->next = s; - else - ctxt->textp = s; - ctxt->etextp = s; - for(s1 = s->sub; s1 != nil; s1 = s1->sub) { - if(s1->onlist) - sysfatal("symbol %s listed multiple times", s1->name); - s1->onlist = 1; - ctxt->etextp->next = s1; - ctxt->etextp = s1; - } - } - } - - // load relocations - for(i=0; iseg.nsect; i++) { - sect = &c->seg.sect[i]; - if((s = sect->sym) == nil) - continue; - macholoadrel(m, sect); - if(sect->rel == nil) - continue; - r = mal(sect->nreloc*sizeof r[0]); - rpi = 0; - for(j=0; jnreloc; j++) { - rp = &r[rpi]; - rel = §->rel[j]; - if(rel->scattered) { - int k; - LdMachoSect *ks; - - if(thearch.thechar != '8') { - // mach-o only uses scattered relocation on 32-bit platforms - diag("unexpected scattered relocation"); - continue; - } - - // on 386, rewrite scattered 4/1 relocation and some - // scattered 2/1 relocation into the pseudo-pc-relative - // reference that it is. - // assume that the second in the pair is in this section - // and use that as the pc-relative base. - if(j+1 >= sect->nreloc) { - werrstr("unsupported scattered relocation %d", (int)rel->type); - goto bad; - } - if(!sect->rel[j+1].scattered || sect->rel[j+1].type != 1 || - (rel->type != 4 && rel->type != 2) || - sect->rel[j+1].value < sect->addr || sect->rel[j+1].value >= sect->addr+sect->size) { - werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)sect->rel[j+1].type); - goto bad; - } - - rp->siz = rel->length; - rp->off = rel->addr; - - // NOTE(rsc): I haven't worked out why (really when) - // we should ignore the addend on a - // scattered relocation, but it seems that the - // common case is we ignore it. - // It's likely that this is not strictly correct - // and that the math should look something - // like the non-scattered case below. - rp->add = 0; - - // want to make it pc-relative aka relative to rp->off+4 - // but the scatter asks for relative to off = sect->rel[j+1].value - sect->addr. - // adjust rp->add accordingly. - rp->type = R_PCREL; - rp->add += (rp->off+4) - (sect->rel[j+1].value - sect->addr); - - // now consider the desired symbol. - // find the section where it lives. - for(k=0; kseg.nsect; k++) { - ks = &c->seg.sect[k]; - if(ks->addr <= rel->value && rel->value < ks->addr+ks->size) - goto foundk; - } - werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr); - goto bad; - foundk: - if(ks->sym != nil) { - rp->sym = ks->sym; - rp->add += rel->value - ks->addr; - } else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) { - // handle reference to __IMPORT/__pointers. - // how much worse can this get? - // why are we supporting 386 on the mac anyway? - rp->type = 512 + MACHO_FAKE_GOTPCREL; - // figure out which pointer this is a reference to. - k = ks->res1 + (rel->value - ks->addr) / 4; - // load indirect table for __pointers - // fetch symbol number - if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) { - werrstr("invalid scattered relocation: indirect symbol reference out of range"); - goto bad; - } - k = dsymtab->indir[k]; - if(k < 0 || k >= symtab->nsym) { - werrstr("invalid scattered relocation: symbol reference out of range"); - goto bad; - } - rp->sym = symtab->sym[k].sym; - } else { - werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name); - goto bad; - } - rpi++; - // skip #1 of 2 rel; continue skips #2 of 2. - j++; - continue; - } - - rp->siz = rel->length; - rp->type = 512 + (rel->type<<1) + rel->pcrel; - rp->off = rel->addr; - - // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0). - if (thearch.thechar == '6' && rel->extrn == 0 && rel->type == 1) { - // Calculate the addend as the offset into the section. - // - // The rip-relative offset stored in the object file is encoded - // as follows: - // - // movsd 0x00000360(%rip),%xmm0 - // - // To get the absolute address of the value this rip-relative address is pointing - // to, we must add the address of the next instruction to it. This is done by - // taking the address of the relocation and adding 4 to it (since the rip-relative - // offset can at most be 32 bits long). To calculate the offset into the section the - // relocation is referencing, we subtract the vaddr of the start of the referenced - // section found in the original object file. - // - // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] - secaddr = c->seg.sect[rel->symnum-1].addr; - rp->add = (int32)e->e32(s->p+rp->off) + rp->off + 4 - secaddr; - } else - rp->add = (int32)e->e32(s->p+rp->off); - - // For i386 Mach-O PC-relative, the addend is written such that - // it *is* the PC being subtracted. Use that to make - // it match our version of PC-relative. - if(rel->pcrel && thearch.thechar == '8') - rp->add += rp->off+rp->siz; - if(!rel->extrn) { - if(rel->symnum < 1 || rel->symnum > c->seg.nsect) { - werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect); - goto bad; - } - rp->sym = c->seg.sect[rel->symnum-1].sym; - if(rp->sym == nil) { - werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name); - goto bad; - } - // References to symbols in other sections - // include that information in the addend. - // We only care about the delta from the - // section base. - if(thearch.thechar == '8') - rp->add -= c->seg.sect[rel->symnum-1].addr; - } else { - if(rel->symnum >= symtab->nsym) { - werrstr("invalid relocation: symbol reference out of range"); - goto bad; - } - rp->sym = symtab->sym[rel->symnum].sym; - } - rpi++; - } - qsort(r, rpi, sizeof r[0], rbyoff); - s->r = r; - s->nr = rpi; - } - return; - -bad: - diag("%s: malformed mach-o file: %r", pn); -} diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c deleted file mode 100644 index e67ad56707..0000000000 --- a/src/cmd/ld/ldpe.c +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include -#include -#include "lib.h" -#include "pe.h" - -enum { - IMAGE_SYM_UNDEFINED = 0, - IMAGE_SYM_ABSOLUTE = (-1), - IMAGE_SYM_DEBUG = (-2), - IMAGE_SYM_TYPE_NULL = 0, - IMAGE_SYM_TYPE_VOID = 1, - IMAGE_SYM_TYPE_CHAR = 2, - IMAGE_SYM_TYPE_SHORT = 3, - IMAGE_SYM_TYPE_INT = 4, - IMAGE_SYM_TYPE_LONG = 5, - IMAGE_SYM_TYPE_FLOAT = 6, - IMAGE_SYM_TYPE_DOUBLE = 7, - IMAGE_SYM_TYPE_STRUCT = 8, - IMAGE_SYM_TYPE_UNION = 9, - IMAGE_SYM_TYPE_ENUM = 10, - IMAGE_SYM_TYPE_MOE = 11, - IMAGE_SYM_TYPE_BYTE = 12, - IMAGE_SYM_TYPE_WORD = 13, - IMAGE_SYM_TYPE_UINT = 14, - IMAGE_SYM_TYPE_DWORD = 15, - IMAGE_SYM_TYPE_PCODE = 32768, - IMAGE_SYM_DTYPE_NULL = 0, - IMAGE_SYM_DTYPE_POINTER = 0x10, - IMAGE_SYM_DTYPE_FUNCTION = 0x20, - IMAGE_SYM_DTYPE_ARRAY = 0x30, - IMAGE_SYM_CLASS_END_OF_FUNCTION = (-1), - IMAGE_SYM_CLASS_NULL = 0, - IMAGE_SYM_CLASS_AUTOMATIC = 1, - IMAGE_SYM_CLASS_EXTERNAL = 2, - IMAGE_SYM_CLASS_STATIC = 3, - IMAGE_SYM_CLASS_REGISTER = 4, - IMAGE_SYM_CLASS_EXTERNAL_DEF = 5, - IMAGE_SYM_CLASS_LABEL = 6, - IMAGE_SYM_CLASS_UNDEFINED_LABEL = 7, - IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8, - IMAGE_SYM_CLASS_ARGUMENT = 9, - IMAGE_SYM_CLASS_STRUCT_TAG = 10, - IMAGE_SYM_CLASS_MEMBER_OF_UNION = 11, - IMAGE_SYM_CLASS_UNION_TAG = 12, - IMAGE_SYM_CLASS_TYPE_DEFINITION = 13, - IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14, - IMAGE_SYM_CLASS_ENUM_TAG = 15, - IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 16, - IMAGE_SYM_CLASS_REGISTER_PARAM = 17, - IMAGE_SYM_CLASS_BIT_FIELD = 18, - IMAGE_SYM_CLASS_FAR_EXTERNAL = 68, /* Not in PECOFF v8 spec */ - IMAGE_SYM_CLASS_BLOCK = 100, - IMAGE_SYM_CLASS_FUNCTION = 101, - IMAGE_SYM_CLASS_END_OF_STRUCT = 102, - IMAGE_SYM_CLASS_FILE = 103, - IMAGE_SYM_CLASS_SECTION = 104, - IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105, - IMAGE_SYM_CLASS_CLR_TOKEN = 107, - - IMAGE_REL_I386_ABSOLUTE = 0x0000, - IMAGE_REL_I386_DIR16 = 0x0001, - IMAGE_REL_I386_REL16 = 0x0002, - IMAGE_REL_I386_DIR32 = 0x0006, - IMAGE_REL_I386_DIR32NB = 0x0007, - IMAGE_REL_I386_SEG12 = 0x0009, - IMAGE_REL_I386_SECTION = 0x000A, - IMAGE_REL_I386_SECREL = 0x000B, - IMAGE_REL_I386_TOKEN = 0x000C, - IMAGE_REL_I386_SECREL7 = 0x000D, - IMAGE_REL_I386_REL32 = 0x0014, - - IMAGE_REL_AMD64_ABSOLUTE = 0x0000, - IMAGE_REL_AMD64_ADDR64 = 0x0001, // R_X86_64_64 - IMAGE_REL_AMD64_ADDR32 = 0x0002, // R_X86_64_PC32 - IMAGE_REL_AMD64_ADDR32NB = 0x0003, - IMAGE_REL_AMD64_REL32 = 0x0004, - IMAGE_REL_AMD64_REL32_1 = 0x0005, - IMAGE_REL_AMD64_REL32_2 = 0x0006, - IMAGE_REL_AMD64_REL32_3 = 0x0007, - IMAGE_REL_AMD64_REL32_4 = 0x0008, - IMAGE_REL_AMD64_REL32_5 = 0x0009, - IMAGE_REL_AMD64_SECTION = 0x000A, - IMAGE_REL_AMD64_SECREL = 0x000B, - IMAGE_REL_AMD64_SECREL7 = 0x000C, - IMAGE_REL_AMD64_TOKEN = 0x000D, - IMAGE_REL_AMD64_SREL32 = 0x000E, - IMAGE_REL_AMD64_PAIR = 0x000F, - IMAGE_REL_AMD64_SSPAN32 = 0x0010, -}; - -typedef struct PeSym PeSym; -typedef struct PeSect PeSect; -typedef struct PeObj PeObj; - -struct PeSym { - char* name; - uint32 value; - uint16 sectnum; - uint16 type; - uint8 sclass; - uint8 aux; - LSym* sym; -}; - -struct PeSect { - char* name; - uchar* base; - uint64 size; - LSym* sym; - IMAGE_SECTION_HEADER sh; -}; - -struct PeObj { - Biobuf *f; - char *name; - uint32 base; - - PeSect *sect; - uint nsect; - PeSym *pesym; - uint npesym; - - IMAGE_FILE_HEADER fh; - char* snames; -}; - -static int pemap(PeObj *peobj, PeSect *sect); -static int issect(PeSym *s); -static int readpesym(PeObj *peobj, int i, PeSym **sym); - -void -ldpe(Biobuf *f, char *pkg, int64 length, char *pn) -{ - char *name; - int32 base; - uint32 l; - int i, j, numaux; - PeObj *peobj; - PeSect *sect, *rsect; - IMAGE_SECTION_HEADER sh; - uchar symbuf[18]; - LSym *s; - Reloc *r, *rp; - PeSym *sym; - - USED(length); - if(debug['v']) - Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn); - - sect = nil; - ctxt->version++; - base = Boffset(f); - - peobj = mal(sizeof *peobj); - peobj->f = f; - peobj->base = base; - peobj->name = pn; - // read header - if(Bread(f, &peobj->fh, sizeof peobj->fh) != sizeof peobj->fh) - goto bad; - // load section list - peobj->sect = mal(peobj->fh.NumberOfSections*sizeof peobj->sect[0]); - peobj->nsect = peobj->fh.NumberOfSections; - for(i=0; i < peobj->fh.NumberOfSections; i++) { - if(Bread(f, &peobj->sect[i].sh, sizeof sh) != sizeof sh) - goto bad; - peobj->sect[i].size = peobj->sect[i].sh.SizeOfRawData; - peobj->sect[i].name = (char*)peobj->sect[i].sh.Name; - // TODO return error if found .cormeta - } - // load string table - Bseek(f, base+peobj->fh.PointerToSymbolTable+sizeof(symbuf)*peobj->fh.NumberOfSymbols, 0); - if(Bread(f, symbuf, 4) != 4) - goto bad; - l = le32(symbuf); - peobj->snames = mal(l); - Bseek(f, base+peobj->fh.PointerToSymbolTable+sizeof(symbuf)*peobj->fh.NumberOfSymbols, 0); - if(Bread(f, peobj->snames, l) != l) - goto bad; - // rewrite section names if they start with / - for(i=0; i < peobj->fh.NumberOfSections; i++) { - if(peobj->sect[i].name == nil) - continue; - if(peobj->sect[i].name[0] != '/') - continue; - l = atoi(peobj->sect[i].name + 1); - peobj->sect[i].name = (char*)&peobj->snames[l]; - } - // read symbols - peobj->pesym = mal(peobj->fh.NumberOfSymbols*sizeof peobj->pesym[0]); - peobj->npesym = peobj->fh.NumberOfSymbols; - Bseek(f, base+peobj->fh.PointerToSymbolTable, 0); - for(i=0; ifh.NumberOfSymbols; i+=numaux+1) { - Bseek(f, base+peobj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0); - if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf) - goto bad; - - if((symbuf[0] == 0) && (symbuf[1] == 0) && - (symbuf[2] == 0) && (symbuf[3] == 0)) { - l = le32(&symbuf[4]); - peobj->pesym[i].name = (char*)&peobj->snames[l]; - } else { // sym name length <= 8 - peobj->pesym[i].name = mal(9); - strncpy(peobj->pesym[i].name, (char*)symbuf, 8); - peobj->pesym[i].name[8] = 0; - } - peobj->pesym[i].value = le32(&symbuf[8]); - peobj->pesym[i].sectnum = le16(&symbuf[12]); - peobj->pesym[i].sclass = symbuf[16]; - peobj->pesym[i].aux = symbuf[17]; - peobj->pesym[i].type = le16(&symbuf[14]); - numaux = peobj->pesym[i].aux; - if (numaux < 0) - numaux = 0; - } - // create symbols for mapped sections - for(i=0; insect; i++) { - sect = &peobj->sect[i]; - if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) - continue; - - if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) { - // This has been seen for .idata sections, which we - // want to ignore. See issues 5106 and 5273. - continue; - } - - if(pemap(peobj, sect) < 0) - goto bad; - - name = smprint("%s(%s)", pkg, sect->name); - s = linklookup(ctxt, name, ctxt->version); - free(name); - switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) { - case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata - s->type = SRODATA; - break; - case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss - s->type = SNOPTRBSS; - break; - case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data - s->type = SNOPTRDATA; - break; - case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text - s->type = STEXT; - break; - default: - werrstr("unexpected flags %#08ux for PE section %s", sect->sh.Characteristics, sect->name); - goto bad; - } - s->p = sect->base; - s->np = sect->size; - s->size = sect->size; - sect->sym = s; - if(strcmp(sect->name, ".rsrc") == 0) - setpersrc(sect->sym); - } - - // load relocations - for(i=0; insect; i++) { - rsect = &peobj->sect[i]; - if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0) - continue; - if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) - continue; - if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) { - // This has been seen for .idata sections, which we - // want to ignore. See issues 5106 and 5273. - continue; - } - r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]); - Bseek(f, peobj->base+rsect->sh.PointerToRelocations, 0); - for(j=0; jsh.NumberOfRelocations; j++) { - rp = &r[j]; - if(Bread(f, symbuf, 10) != 10) - goto bad; - - uint32 rva, symindex; - uint16 type; - rva = le32(&symbuf[0]); - symindex = le32(&symbuf[4]); - type = le16(&symbuf[8]); - if(readpesym(peobj, symindex, &sym) < 0) - goto bad; - if(sym->sym == nil) { - werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type); - goto bad; - } - rp->sym = sym->sym; - rp->siz = 4; - rp->off = rva; - switch(type) { - default: - diag("%s: unknown relocation type %d;", pn, type); - case IMAGE_REL_I386_REL32: - case IMAGE_REL_AMD64_REL32: - case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32 - case IMAGE_REL_AMD64_ADDR32NB: - rp->type = R_PCREL; - rp->add = (int32)le32(rsect->base+rp->off); - break; - case IMAGE_REL_I386_DIR32NB: - case IMAGE_REL_I386_DIR32: - rp->type = R_ADDR; - // load addend from image - rp->add = (int32)le32(rsect->base+rp->off); - break; - case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 - rp->siz = 8; - rp->type = R_ADDR; - // load addend from image - rp->add = le64(rsect->base+rp->off); - break; - } - // ld -r could generate multiple section symbols for the - // same section but with different values, we have to take - // that into account - if(issect(&peobj->pesym[symindex])) - rp->add += peobj->pesym[symindex].value; - } - qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff); - - s = rsect->sym; - s->r = r; - s->nr = rsect->sh.NumberOfRelocations; - } - - // enter sub-symbols into symbol table. - for(i=0; inpesym; i++) { - if(peobj->pesym[i].name == 0) - continue; - if(issect(&peobj->pesym[i])) - continue; - if(peobj->pesym[i].sectnum > peobj->nsect) - continue; - if(peobj->pesym[i].sectnum > 0) { - sect = &peobj->sect[peobj->pesym[i].sectnum-1]; - if(sect->sym == 0) - continue; - } - if(readpesym(peobj, i, &sym) < 0) - goto bad; - - s = sym->sym; - if(sym->sectnum == 0) {// extern - if(s->type == SDYNIMPORT) - s->plt = -2; // flag for dynimport in PE object files. - if (s->type == SXREF && sym->value > 0) {// global data - s->type = SNOPTRDATA; - s->size = sym->value; - } - continue; - } else if (sym->sectnum > 0 && sym->sectnum <= peobj->nsect) { - sect = &peobj->sect[sym->sectnum-1]; - if(sect->sym == 0) - diag("%s: %s sym == 0!", pn, s->name); - } else { - diag("%s: %s sectnum < 0!", pn, s->name); - } - - if(sect == nil) - return; - - if(s->outer != nil) { - if(s->dupok) - continue; - diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); - errorexit(); - } - s->sub = sect->sym->sub; - sect->sym->sub = s; - s->type = sect->sym->type | SSUB; - s->value = sym->value; - s->size = 4; - s->outer = sect->sym; - if(sect->sym->type == STEXT) { - if(s->external && !s->dupok) - diag("%s: duplicate definition of %s", pn, s->name); - s->external = 1; - } - } - - // Sort outer lists by address, adding to textp. - // This keeps textp in increasing address order. - for(i=0; insect; i++) { - s = peobj->sect[i].sym; - if(s == nil) - continue; - if(s->sub) - s->sub = listsort(s->sub, valuecmp, listsubp); - if(s->type == STEXT) { - if(s->onlist) - sysfatal("symbol %s listed multiple times", s->name); - s->onlist = 1; - if(ctxt->etextp) - ctxt->etextp->next = s; - else - ctxt->textp = s; - ctxt->etextp = s; - for(s = s->sub; s != nil; s = s->sub) { - if(s->onlist) - sysfatal("symbol %s listed multiple times", s->name); - s->onlist = 1; - ctxt->etextp->next = s; - ctxt->etextp = s; - } - } - } - - return; -bad: - diag("%s: malformed pe file: %r", pn); -} - -static int -pemap(PeObj *peobj, PeSect *sect) -{ - if(sect->base != nil) - return 0; - - sect->base = mal(sect->sh.SizeOfRawData); - if(sect->sh.PointerToRawData == 0) // .bss doesn't have data in object file - return 0; - werrstr("short read"); - if(Bseek(peobj->f, peobj->base+sect->sh.PointerToRawData, 0) < 0 || - Bread(peobj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData) - return -1; - - return 0; -} - -static int -issect(PeSym *s) -{ - return s->sclass == IMAGE_SYM_CLASS_STATIC && s->type == 0 && s->name[0] == '.'; -} - -static int -readpesym(PeObj *peobj, int i, PeSym **y) -{ - LSym *s; - PeSym *sym; - char *name, *p; - - if(i >= peobj->npesym || i < 0) { - werrstr("invalid pe symbol index"); - return -1; - } - - sym = &peobj->pesym[i]; - *y = sym; - - if(issect(sym)) - name = peobj->sect[sym->sectnum-1].sym->name; - else { - name = sym->name; - if(strncmp(name, "__imp_", 6) == 0) - name = &name[6]; // __imp_Name => Name - if(thearch.thechar == '8' && name[0] == '_') - name = &name[1]; // _Name => Name - } - // remove last @XXX - p = strchr(name, '@'); - if(p) - *p = 0; - - switch(sym->type) { - default: - werrstr("%s: invalid symbol type %d", sym->name, sym->type); - return -1; - case IMAGE_SYM_DTYPE_FUNCTION: - case IMAGE_SYM_DTYPE_NULL: - switch(sym->sclass) { - case IMAGE_SYM_CLASS_EXTERNAL: //global - s = linklookup(ctxt, name, 0); - break; - case IMAGE_SYM_CLASS_NULL: - case IMAGE_SYM_CLASS_STATIC: - case IMAGE_SYM_CLASS_LABEL: - s = linklookup(ctxt, name, ctxt->version); - s->dupok = 1; - break; - default: - werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass); - return -1; - } - break; - } - - if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0)) - s->type = SXREF; - if(strncmp(sym->name, "__imp_", 6) == 0) - s->got = -2; // flag for __imp_ - sym->sym = s; - - return 0; -} diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c deleted file mode 100644 index 612c755d5b..0000000000 --- a/src/cmd/ld/lib.c +++ /dev/null @@ -1,1636 +0,0 @@ -// Derived from Inferno utils/6l/obj.c and utils/6l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include -#include -#include "lib.h" -#include "elf.h" -#include "dwarf.h" -#include "../../runtime/stack.h" -#include "../../runtime/funcdata.h" - -#include -#if !(defined(_WIN32) || defined(PLAN9)) -#include -#endif - -enum -{ - // Whether to assume that the external linker is "gold" - // (http://sourceware.org/ml/binutils/2008-03/msg00162.html). - AssumeGoldLinker = 0, -}; - -int iconv(Fmt*); - -char symname[] = "__.GOSYMDEF"; -char pkgname[] = "__.PKGDEF"; -static int cout = -1; - -extern int version; - -// Set if we see an object compiled by the host compiler that is not -// from a package that is known to support internal linking mode. -static int externalobj = 0; - -static void hostlinksetup(void); - -char* goroot; -char* goarch; -char* goos; -char* theline; - -void -Lflag(char *arg) -{ - char **p; - - if(ctxt->nlibdir >= ctxt->maxlibdir) { - if (ctxt->maxlibdir == 0) - ctxt->maxlibdir = 8; - else - ctxt->maxlibdir *= 2; - p = erealloc(ctxt->libdir, ctxt->maxlibdir * sizeof(*p)); - ctxt->libdir = p; - } - ctxt->libdir[ctxt->nlibdir++] = arg; -} - -/* - * Unix doesn't like it when we write to a running (or, sometimes, - * recently run) binary, so remove the output file before writing it. - * On Windows 7, remove() can force a subsequent create() to fail. - * S_ISREG() does not exist on Plan 9. - */ -static void -mayberemoveoutfile(void) -{ -#if !(defined(_WIN32) || defined(PLAN9)) - struct stat st; - if(lstat(outfile, &st) == 0 && !S_ISREG(st.st_mode)) - return; -#endif - remove(outfile); -} - -void -libinit(void) -{ - char *suffix, *suffixsep; - - funcalign = thearch.funcalign; - fmtinstall('i', iconv); - fmtinstall('Y', Yconv); - fmtinstall('Z', Zconv); - mywhatsys(); // get goroot, goarch, goos - - // add goroot to the end of the libdir list. - suffix = ""; - suffixsep = ""; - if(flag_installsuffix != nil) { - suffixsep = "_"; - suffix = flag_installsuffix; - } else if(flag_race) { - suffixsep = "_"; - suffix = "race"; - } - Lflag(smprint("%s/pkg/%s_%s%s%s", goroot, goos, goarch, suffixsep, suffix)); - - mayberemoveoutfile(); - cout = create(outfile, 1, 0775); - if(cout < 0) { - diag("cannot create %s: %r", outfile); - errorexit(); - } - Binit(&coutbuf, cout, OWRITE); - - if(INITENTRY == nil) { - INITENTRY = mal(strlen(goarch)+strlen(goos)+20); - if(!flag_shared) { - sprint(INITENTRY, "_rt0_%s_%s", goarch, goos); - } else { - sprint(INITENTRY, "_rt0_%s_%s_lib", goarch, goos); - } - } - linklookup(ctxt, INITENTRY, 0)->type = SXREF; -} - -void -errorexit(void) -{ - if(cout >= 0) { - // For rmtemp run at atexit time on Windows. - close(cout); - } - if(nerrors) { - if(cout >= 0) - mayberemoveoutfile(); - exits("error"); - } - exits(0); -} - -void -loadinternal(char *name) -{ - char pname[1024]; - int i, found; - - found = 0; - for(i=0; inlibdir; i++) { - snprint(pname, sizeof pname, "%s/%s.a", ctxt->libdir[i], name); - if(debug['v']) - Bprint(&bso, "searching for %s.a in %s\n", name, pname); - if(access(pname, AEXIST) >= 0) { - addlibpath(ctxt, "internal", "internal", pname, name); - found = 1; - break; - } - } - if(!found) - Bprint(&bso, "warning: unable to find %s.a\n", name); -} - -void -loadlib(void) -{ - int i, w, x; - LSym *s, *tlsg; - char* cgostrsym; - - if(flag_shared) { - s = linklookup(ctxt, "runtime.islibrary", 0); - s->dupok = 1; - adduint8(ctxt, s, 1); - } - - loadinternal("runtime"); - if(thearch.thechar == '5') - loadinternal("math"); - if(flag_race) - loadinternal("runtime/race"); - - for(i=0; ilibraryp; i++) { - if(debug['v'] > 1) - Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), ctxt->library[i].file, ctxt->library[i].objref); - iscgo |= strcmp(ctxt->library[i].pkg, "runtime/cgo") == 0; - objfile(ctxt->library[i].file, ctxt->library[i].pkg); - } - - if(linkmode == LinkAuto) { - if(iscgo && externalobj) - linkmode = LinkExternal; - else - linkmode = LinkInternal; - - // Force external linking for android. - if(strcmp(goos, "android") == 0) - linkmode = LinkExternal; - - // cgo on Darwin must use external linking - // we can always use external linking, but then there will be circular - // dependency problems when compiling natively (external linking requires - // runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be - // compiled using external linking.) - if(thearch.thechar == '5' && HEADTYPE == Hdarwin && iscgo) - linkmode = LinkExternal; - } - - if(linkmode == LinkExternal && !iscgo) { - // This indicates a user requested -linkmode=external. - // The startup code uses an import of runtime/cgo to decide - // whether to initialize the TLS. So give it one. This could - // be handled differently but it's an unusual case. - loadinternal("runtime/cgo"); - if(i < ctxt->libraryp) - objfile(ctxt->library[i].file, ctxt->library[i].pkg); - - // Pretend that we really imported the package. - s = linklookup(ctxt, "go.importpath.runtime/cgo.", 0); - s->type = SDATA; - s->dupok = 1; - s->reachable = 1; - - // Provided by the code that imports the package. - // Since we are simulating the import, we have to provide this string. - cgostrsym = "go.string.\"runtime/cgo\""; - if(linkrlookup(ctxt, cgostrsym, 0) == nil) { - s = linklookup(ctxt, cgostrsym, 0); - s->type = SRODATA; - s->reachable = 1; - addstrdata(cgostrsym, "runtime/cgo"); - } - } - - if(linkmode == LinkInternal) { - // Drop all the cgo_import_static declarations. - // Turns out we won't be needing them. - for(s = ctxt->allsym; s != nil; s = s->allsym) - if(s->type == SHOSTOBJ) { - // If a symbol was marked both - // cgo_import_static and cgo_import_dynamic, - // then we want to make it cgo_import_dynamic - // now. - if(s->extname != nil && s->dynimplib != nil && s->cgoexport == 0) { - s->type = SDYNIMPORT; - } else - s->type = 0; - } - } - - tlsg = linklookup(ctxt, "runtime.tlsg", 0); - // For most ports, runtime.tlsg is a placeholder symbol for TLS - // relocation. However, the Android and Darwin arm ports need it - // to be a real variable. - // - // TODO(crawshaw): android should require leaving the tlsg->type - // alone (as the runtime-provided SNOPTRBSS) just like darwin/arm. - // But some other part of the linker is expecting STLSBSS. - if (!(strcmp(goos, "darwin") == 0 && thearch.thechar == '5')) - tlsg->type = STLSBSS; - tlsg->size = thearch.ptrsize; - tlsg->hide = 1; - tlsg->reachable = 1; - ctxt->tlsg = tlsg; - - // Now that we know the link mode, trim the dynexp list. - x = CgoExportDynamic; - if(linkmode == LinkExternal) - x = CgoExportStatic; - w = 0; - for(i=0; icgoexport & x) - dynexp[w++] = dynexp[i]; - ndynexp = w; - - // In internal link mode, read the host object files. - if(linkmode == LinkInternal) - hostobjs(); - else - hostlinksetup(); - - // We've loaded all the code now. - // If there are no dynamic libraries needed, gcc disables dynamic linking. - // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13) - // assumes that a dynamic binary always refers to at least one dynamic library. - // Rather than be a source of test cases for glibc, disable dynamic linking - // the same way that gcc would. - // - // Exception: on OS X, programs such as Shark only work with dynamic - // binaries, so leave it enabled on OS X (Mach-O) binaries. - // Also leave it enabled on Solaris which doesn't support - // statically linked binaries. - if(!flag_shared && !havedynamic && HEADTYPE != Hdarwin && HEADTYPE != Hsolaris) - debug['d'] = 1; - - importcycles(); -} - -/* - * look for the next file in an archive. - * adapted from libmach. - */ -static vlong -nextar(Biobuf *bp, vlong off, ArHdr *a) -{ - int r; - int32 arsize; - char *buf; - - if (off&01) - off++; - Bseek(bp, off, 0); - buf = Brdline(bp, '\n'); - r = Blinelen(bp); - if(buf == nil) { - if(r == 0) - return 0; - return -1; - } - if(r != SAR_HDR) - return -1; - memmove(a, buf, SAR_HDR); - if(strncmp(a->fmag, ARFMAG, sizeof a->fmag)) - return -1; - arsize = strtol(a->size, 0, 0); - if (arsize&1) - arsize++; - return arsize + r; -} - -void -objfile(char *file, char *pkg) -{ - vlong off, l; - Biobuf *f; - char magbuf[SARMAG]; - char pname[150]; - ArHdr arhdr; - - pkg = smprint("%i", pkg); - - if(debug['v'] > 1) - Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg); - Bflush(&bso); - f = Bopen(file, 0); - if(f == nil) { - diag("cannot open file: %s", file); - errorexit(); - } - l = Bread(f, magbuf, SARMAG); - if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){ - /* load it as a regular file */ - l = Bseek(f, 0L, 2); - Bseek(f, 0L, 0); - ldobj(f, pkg, l, file, file, FileObj); - Bterm(f); - free(pkg); - return; - } - - /* skip over optional __.GOSYMDEF and process __.PKGDEF */ - off = Boffset(f); - l = nextar(f, off, &arhdr); - if(l <= 0) { - diag("%s: short read on archive file symbol header", file); - goto out; - } - if(strncmp(arhdr.name, symname, strlen(symname)) == 0) { - off += l; - l = nextar(f, off, &arhdr); - if(l <= 0) { - diag("%s: short read on archive file symbol header", file); - goto out; - } - } - - if(strncmp(arhdr.name, pkgname, strlen(pkgname))) { - diag("%s: cannot find package header", file); - goto out; - } - off += l; - - if(debug['u']) - ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef); - - /* - * load all the object files from the archive now. - * this gives us sequential file access and keeps us - * from needing to come back later to pick up more - * objects. it breaks the usual C archive model, but - * this is Go, not C. the common case in Go is that - * we need to load all the objects, and then we throw away - * the individual symbols that are unused. - * - * loading every object will also make it possible to - * load foreign objects not referenced by __.GOSYMDEF. - */ - for(;;) { - l = nextar(f, off, &arhdr); - if(l == 0) - break; - if(l < 0) { - diag("%s: malformed archive", file); - goto out; - } - off += l; - - l = SARNAME; - while(l > 0 && arhdr.name[l-1] == ' ') - l--; - snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name); - l = atolwhex(arhdr.size); - ldobj(f, pkg, l, pname, file, ArchiveObj); - } - -out: - Bterm(f); - free(pkg); -} - -static void -dowrite(int fd, char *p, int n) -{ - int m; - - while(n > 0) { - m = write(fd, p, n); - if(m <= 0) { - ctxt->cursym = nil; - diag("write error: %r"); - errorexit(); - } - n -= m; - p += m; - } -} - -typedef struct Hostobj Hostobj; - -struct Hostobj -{ - void (*ld)(Biobuf*, char*, int64, char*); - char *pkg; - char *pn; - char *file; - int64 off; - int64 length; -}; - -Hostobj *hostobj; -int nhostobj; -int mhostobj; - -// These packages can use internal linking mode. -// Others trigger external mode. -const char *internalpkg[] = { - "crypto/x509", - "net", - "os/user", - "runtime/cgo", - "runtime/race" -}; - -void -ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 length, char *pn, char *file) -{ - int i, isinternal; - Hostobj *h; - - isinternal = 0; - for(i=0; i= mhostobj) { - if(mhostobj == 0) - mhostobj = 16; - else - mhostobj *= 2; - hostobj = erealloc(hostobj, mhostobj*sizeof hostobj[0]); - } - h = &hostobj[nhostobj++]; - h->ld = ld; - h->pkg = estrdup(pkg); - h->pn = estrdup(pn); - h->file = estrdup(file); - h->off = Boffset(f); - h->length = length; -} - -void -hostobjs(void) -{ - int i; - Biobuf *f; - Hostobj *h; - - for(i=0; ifile, OREAD); - if(f == nil) { - ctxt->cursym = nil; - diag("cannot reopen %s: %r", h->pn); - errorexit(); - } - Bseek(f, h->off, 0); - h->ld(f, h->pkg, h->length, h->pn); - Bterm(f); - } -} - -// provided by lib9 -int runcmd(char**); -char* mktempdir(void); -void removeall(char*); - -static void -rmtemp(void) -{ - removeall(tmpdir); -} - -static void -hostlinksetup(void) -{ - char *p; - - if(linkmode != LinkExternal) - return; - - // create temporary directory and arrange cleanup - if(tmpdir == nil) { - tmpdir = mktempdir(); - atexit(rmtemp); - } - - // change our output to temporary object file - close(cout); - p = smprint("%s/go.o", tmpdir); - cout = create(p, 1, 0775); - if(cout < 0) { - diag("cannot create %s: %r", p); - errorexit(); - } - Binit(&coutbuf, cout, OWRITE); - free(p); -} - -void -hostlink(void) -{ - char *p, **argv; - int c, i, w, n, argc, length; - Hostobj *h; - Biobuf *f; - static char buf[64<<10]; - - if(linkmode != LinkExternal || nerrors > 0) - return; - - c = 0; - p = extldflags; - while(p != nil) { - while(*p == ' ') - p++; - if(*p == '\x00') - break; - c++; - p = strchr(p + 1, ' '); - } - - argv = malloc((14+nhostobj+nldflag+c)*sizeof argv[0]); - argc = 0; - if(extld == nil) - extld = "gcc"; - argv[argc++] = extld; - switch(thearch.thechar){ - case '8': - argv[argc++] = "-m32"; - break; - case '6': - case '9': - argv[argc++] = "-m64"; - break; - case '5': - argv[argc++] = "-marm"; - break; - } - if(!debug['s'] && !debug_s) { - argv[argc++] = "-gdwarf-2"; - } else { - argv[argc++] = "-s"; - } - if(HEADTYPE == Hdarwin) - argv[argc++] = "-Wl,-no_pie,-pagezero_size,4000000"; - if(HEADTYPE == Hopenbsd) - argv[argc++] = "-Wl,-nopie"; - - if(iself && AssumeGoldLinker) - argv[argc++] = "-Wl,--rosegment"; - - if(flag_shared) { - argv[argc++] = "-Wl,-Bsymbolic"; - argv[argc++] = "-shared"; - } - argv[argc++] = "-o"; - argv[argc++] = outfile; - - if(rpath) - argv[argc++] = smprint("-Wl,-rpath,%s", rpath); - - // Force global symbols to be exported for dlopen, etc. - if(iself) - argv[argc++] = "-rdynamic"; - - if(strstr(argv[0], "clang") != nil) - argv[argc++] = "-Qunused-arguments"; - - // already wrote main object file - // copy host objects to temporary directory - for(i=0; ifile, OREAD); - if(f == nil) { - ctxt->cursym = nil; - diag("cannot reopen %s: %r", h->pn); - errorexit(); - } - Bseek(f, h->off, 0); - p = smprint("%s/%06d.o", tmpdir, i); - argv[argc++] = p; - w = create(p, 1, 0775); - if(w < 0) { - ctxt->cursym = nil; - diag("cannot create %s: %r", p); - errorexit(); - } - length = h->length; - while(length > 0) { - n = Bread(f, buf, sizeof buf); - if(n <= 0) - break; - if(n > length) - n = length; - dowrite(w, buf, n); - length -= n; - } - if(close(w) < 0) { - ctxt->cursym = nil; - diag("cannot write %s: %r", p); - errorexit(); - } - Bterm(f); - } - - argv[argc++] = smprint("%s/go.o", tmpdir); - for(i=0; icursym = nil; - diag("%s: running %s failed: %r", argv0, argv[0]); - errorexit(); - } -} - -void -ldobj(Biobuf *f, char *pkg, int64 length, char *pn, char *file, int whence) -{ - char *line; - int n, c1, c2, c3, c4; - uint32 magic; - vlong import0, import1, eof, start; - char *t; - - eof = Boffset(f) + length; - - pn = estrdup(pn); - - start = Boffset(f); - c1 = BGETC(f); - c2 = BGETC(f); - c3 = BGETC(f); - c4 = BGETC(f); - Bseek(f, start, 0); - - magic = c1<<24 | c2<<16 | c3<<8 | c4; - if(magic == 0x7f454c46) { // \x7F E L F - ldhostobj(ldelf, f, pkg, length, pn, file); - return; - } - if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) { - ldhostobj(ldmacho, f, pkg, length, pn, file); - return; - } - if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) { - ldhostobj(ldpe, f, pkg, length, pn, file); - return; - } - - /* check the header */ - line = Brdline(f, '\n'); - if(line == nil) { - if(Blinelen(f) > 0) { - diag("%s: not an object file", pn); - return; - } - goto eof; - } - n = Blinelen(f) - 1; - line[n] = '\x00'; - if(strncmp(line, "go object ", 10) != 0) { - if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) { - print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thearch.thechar, pn, thearch.thechar, thearch.thechar); - errorexit(); - } - if(strcmp(line, thestring) == 0) { - // old header format: just $GOOS - diag("%s: stale object file", pn); - return; - } - diag("%s: not an object file", pn); - free(pn); - return; - } - - // First, check that the basic goos, goarch, and version match. - t = smprint("%s %s %s ", goos, getgoarch(), getgoversion()); - line[n] = ' '; - if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) { - line[n] = '\x00'; - diag("%s: object is [%s] expected [%s]", pn, line+10, t); - free(t); - free(pn); - return; - } - - // Second, check that longer lines match each other exactly, - // so that the Go compiler and write additional information - // that must be the same from run to run. - line[n] = '\x00'; - if(n-10 > strlen(t)) { - if(theline == nil) - theline = estrdup(line+10); - else if(strcmp(theline, line+10) != 0) { - line[n] = '\x00'; - diag("%s: object is [%s] expected [%s]", pn, line+10, theline); - free(t); - free(pn); - return; - } - } - free(t); - line[n] = '\n'; - - /* skip over exports and other info -- ends with \n!\n */ - import0 = Boffset(f); - c1 = '\n'; // the last line ended in \n - c2 = BGETC(f); - c3 = BGETC(f); - while(c1 != '\n' || c2 != '!' || c3 != '\n') { - c1 = c2; - c2 = c3; - c3 = BGETC(f); - if(c3 == Beof) - goto eof; - } - import1 = Boffset(f); - - Bseek(f, import0, 0); - ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n - Bseek(f, import1, 0); - - ldobjfile(ctxt, f, pkg, eof - Boffset(f), pn); - free(pn); - return; - -eof: - diag("truncated object file: %s", pn); - free(pn); -} - -void -zerosig(char *sp) -{ - LSym *s; - - s = linklookup(ctxt, sp, 0); - s->sig = 0; -} - -void -mywhatsys(void) -{ - goroot = getgoroot(); - goos = getgoos(); - goarch = getgoarch(); - - if(strncmp(goarch, thestring, strlen(thestring)) != 0) - sysfatal("cannot use %cc with GOARCH=%s", thearch.thechar, goarch); -} - -int -pathchar(void) -{ - return '/'; -} - -static uchar* hunk; -static uint32 nhunk; -enum { - NHUNK = 10<<20, -}; - -void* -mal(uint32 n) -{ - void *v; - - n = (n+7)&~7; - if(n > NHUNK) { - v = malloc(n); - if(v == nil) { - diag("out of memory"); - errorexit(); - } - memset(v, 0, n); - return v; - } - if(n > nhunk) { - hunk = malloc(NHUNK); - if(hunk == nil) { - diag("out of memory"); - errorexit(); - } - nhunk = NHUNK; - } - - v = hunk; - nhunk -= n; - hunk += n; - - memset(v, 0, n); - return v; -} - -void -unmal(void *v, uint32 n) -{ - n = (n+7)&~7; - if(hunk - n == v) { - hunk -= n; - nhunk += n; - } -} - -// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync. -/* - * Convert raw string to the prefix that will be used in the symbol table. - * Invalid bytes turn into %xx. Right now the only bytes that need - * escaping are %, ., and ", but we escape all control characters too. - * - * If you edit this, edit ../gc/subr.c:/^pathtoprefix too. - * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too. - */ -static char* -pathtoprefix(char *s) -{ - static char hex[] = "0123456789abcdef"; - char *p, *r, *w, *l; - int n; - - // find first character past the last slash, if any. - l = s; - for(r=s; *r; r++) - if(*r == '/') - l = r+1; - - // check for chars that need escaping - n = 0; - for(r=s; *r; r++) - if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) - n++; - - // quick exit - if(n == 0) - return s; - - // escape - p = mal((r-s)+1+2*n); - for(r=s, w=p; *r; r++) { - if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) { - *w++ = '%'; - *w++ = hex[(*r>>4)&0xF]; - *w++ = hex[*r&0xF]; - } else - *w++ = *r; - } - *w = '\x00'; - return p; -} - -int -iconv(Fmt *fp) -{ - char *p; - - p = va_arg(fp->args, char*); - if(p == nil) { - fmtstrcpy(fp, ""); - return 0; - } - p = pathtoprefix(p); - fmtstrcpy(fp, p); - return 0; -} - -Section* -addsection(Segment *seg, char *name, int rwx) -{ - Section **l; - Section *sect; - - for(l=&seg->sect; *l; l=&(*l)->next) - ; - sect = mal(sizeof *sect); - sect->rwx = rwx; - sect->name = name; - sect->seg = seg; - sect->align = thearch.ptrsize; // everything is at least pointer-aligned - *l = sect; - return sect; -} - -uint16 -le16(uchar *b) -{ - return b[0] | b[1]<<8; -} - -uint32 -le32(uchar *b) -{ - return b[0] | b[1]<<8 | b[2]<<16 | (uint32)b[3]<<24; -} - -uint64 -le64(uchar *b) -{ - return le32(b) | (uint64)le32(b+4)<<32; -} - -uint16 -be16(uchar *b) -{ - return b[0]<<8 | b[1]; -} - -uint32 -be32(uchar *b) -{ - return (uint32)b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3]; -} - -uint64 -be64(uchar *b) -{ - return (uvlong)be32(b)<<32 | be32(b+4); -} - -Endian be = { be16, be32, be64 }; -Endian le = { le16, le32, le64 }; - -typedef struct Chain Chain; -struct Chain -{ - LSym *sym; - Chain *up; - int limit; // limit on entry to sym -}; - -static int stkcheck(Chain*, int); -static void stkprint(Chain*, int); -static void stkbroke(Chain*, int); -static LSym *morestack; -static LSym *newstack; - -// TODO: Record enough information in new object files to -// allow stack checks here. - -static int -haslinkregister(void) -{ - return thearch.thechar == '5' || thearch.thechar == '9'; -} - -static int -callsize(void) -{ - if(haslinkregister()) - return 0; - return thearch.regsize; -} - -void -dostkcheck(void) -{ - Chain ch; - LSym *s; - - morestack = linklookup(ctxt, "runtime.morestack", 0); - newstack = linklookup(ctxt, "runtime.newstack", 0); - - // Every splitting function ensures that there are at least StackLimit - // bytes available below SP when the splitting prologue finishes. - // If the splitting function calls F, then F begins execution with - // at least StackLimit - callsize() bytes available. - // Check that every function behaves correctly with this amount - // of stack, following direct calls in order to piece together chains - // of non-splitting functions. - ch.up = nil; - ch.limit = StackLimit - callsize(); - - // Check every function, but do the nosplit functions in a first pass, - // to make the printed failure chains as short as possible. - for(s = ctxt->textp; s != nil; s = s->next) { - // runtime.racesymbolizethunk is called from gcc-compiled C - // code running on the operating system thread stack. - // It uses more than the usual amount of stack but that's okay. - if(strcmp(s->name, "runtime.racesymbolizethunk") == 0) - continue; - - if(s->nosplit) { - ctxt->cursym = s; - ch.sym = s; - stkcheck(&ch, 0); - } - } - for(s = ctxt->textp; s != nil; s = s->next) { - if(!s->nosplit) { - ctxt->cursym = s; - ch.sym = s; - stkcheck(&ch, 0); - } - } -} - -static int -stkcheck(Chain *up, int depth) -{ - Chain ch, ch1; - LSym *s; - int limit; - Reloc *r; - int ri, endr; - Pciter pcsp; - - limit = up->limit; - s = up->sym; - - // Don't duplicate work: only need to consider each - // function at top of safe zone once. - if(limit == StackLimit-callsize()) { - if(s->stkcheck) - return 0; - s->stkcheck = 1; - } - - if(depth > 100) { - diag("nosplit stack check too deep"); - stkbroke(up, 0); - return -1; - } - - if(s->external || s->pcln == nil) { - // external function. - // should never be called directly. - // only diagnose the direct caller. - if(depth == 1 && s->type != SXREF) - diag("call to external function %s", s->name); - return -1; - } - - if(limit < 0) { - stkbroke(up, limit); - return -1; - } - - // morestack looks like it calls functions, - // but it switches the stack pointer first. - if(s == morestack) - return 0; - - ch.up = up; - - // Walk through sp adjustments in function, consuming relocs. - ri = 0; - endr = s->nr; - for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) { - // pcsp.value is in effect for [pcsp.pc, pcsp.nextpc). - - // Check stack size in effect for this span. - if(limit - pcsp.value < 0) { - stkbroke(up, limit - pcsp.value); - return -1; - } - - // Process calls in this span. - for(; ri < endr && s->r[ri].off < pcsp.nextpc; ri++) { - r = &s->r[ri]; - switch(r->type) { - case R_CALL: - case R_CALLARM: - case R_CALLPOWER: - // Direct call. - ch.limit = limit - pcsp.value - callsize(); - ch.sym = r->sym; - if(stkcheck(&ch, depth+1) < 0) - return -1; - - // If this is a call to morestack, we've just raised our limit back - // to StackLimit beyond the frame size. - if(strncmp(r->sym->name, "runtime.morestack", 17) == 0) { - limit = StackLimit + s->locals; - if(haslinkregister()) - limit += thearch.regsize; - } - break; - - case R_CALLIND: - // Indirect call. Assume it is a call to a splitting function, - // so we have to make sure it can call morestack. - // Arrange the data structures to report both calls, so that - // if there is an error, stkprint shows all the steps involved. - ch.limit = limit - pcsp.value - callsize(); - ch.sym = nil; - ch1.limit = ch.limit - callsize(); // for morestack in called prologue - ch1.up = &ch; - ch1.sym = morestack; - if(stkcheck(&ch1, depth+2) < 0) - return -1; - break; - } - } - } - - return 0; -} - -static void -stkbroke(Chain *ch, int limit) -{ - diag("nosplit stack overflow"); - stkprint(ch, limit); -} - -static void -stkprint(Chain *ch, int limit) -{ - char *name; - - if(ch->sym) - name = ch->sym->name; - else - name = "function pointer"; - - if(ch->up == nil) { - // top of chain. ch->sym != nil. - if(ch->sym->nosplit) - print("\t%d\tassumed on entry to %s\n", ch->limit, name); - else - print("\t%d\tguaranteed after split check in %s\n", ch->limit, name); - } else { - stkprint(ch->up, ch->limit + callsize()); - if(!haslinkregister()) - print("\t%d\ton entry to %s\n", ch->limit, name); - } - if(ch->limit != limit) - print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit); -} - -int -Yconv(Fmt *fp) -{ - LSym *s; - Fmt fmt; - int i; - char *str; - - s = va_arg(fp->args, LSym*); - if (s == nil) { - fmtprint(fp, ""); - } else { - fmtstrinit(&fmt); - fmtprint(&fmt, "%s @0x%08llx [%lld]", s->name, (vlong)s->value, (vlong)s->size); - for (i = 0; i < s->size; i++) { - if (!(i%8)) fmtprint(&fmt, "\n\t0x%04x ", i); - fmtprint(&fmt, "%02x ", s->p[i]); - } - fmtprint(&fmt, "\n"); - for (i = 0; i < s->nr; i++) { - fmtprint(&fmt, "\t0x%04x[%x] %d %s[%llx]\n", - s->r[i].off, - s->r[i].siz, - s->r[i].type, - s->r[i].sym->name, - (vlong)s->r[i].add); - } - str = fmtstrflush(&fmt); - fmtstrcpy(fp, str); - free(str); - } - - return 0; -} - -void -cflush(void) -{ - Bflush(&coutbuf); -} - -vlong -cpos(void) -{ - return Boffset(&coutbuf); -} - -void -cseek(vlong p) -{ - Bseek(&coutbuf, p, 0); -} - -void -cwrite(void *buf, int n) -{ - Bflush(&coutbuf); // TODO: Remove if safe. - Bwrite(&coutbuf, buf, n); -} - -void -cput(uint8 c) -{ - Bputc(&coutbuf, c); -} - -void -usage(void) -{ - fprint(2, "usage: %cl [options] main.%c\n", thearch.thechar, thearch.thechar); - flagprint(2); - exits("usage"); -} - -void -setheadtype(char *s) -{ - int h; - - h = headtype(s); - if(h < 0) { - fprint(2, "unknown header type -H %s\n", s); - errorexit(); - } - headstring = s; - HEADTYPE = headtype(s); -} - -void -setinterp(char *s) -{ - debug['I'] = 1; // denote cmdline interpreter override - interpreter = s; -} - -void -doversion(void) -{ - print("%cl version %s\n", thearch.thechar, getgoversion()); - errorexit(); -} - -void -genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) -{ - Auto *a; - LSym *s; - int32 off; - - // These symbols won't show up in the first loop below because we - // skip STEXT symbols. Normal STEXT symbols are emitted by walking textp. - s = linklookup(ctxt, "runtime.text", 0); - if(s->type == STEXT) - put(s, s->name, 'T', s->value, s->size, s->version, 0); - s = linklookup(ctxt, "runtime.etext", 0); - if(s->type == STEXT) - put(s, s->name, 'T', s->value, s->size, s->version, 0); - - for(s=ctxt->allsym; s!=nil; s=s->allsym) { - if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0)) - continue; - switch(s->type&SMASK) { - case SCONST: - case SRODATA: - case SSYMTAB: - case SPCLNTAB: - case SDATA: - case SNOPTRDATA: - case SELFROSECT: - case SMACHOGOT: - case STYPE: - case SSTRING: - case SGOSTRING: - case SWINDOWS: - if(!s->reachable) - continue; - put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype); - continue; - - case SBSS: - case SNOPTRBSS: - if(!s->reachable) - continue; - if(s->np > 0) - diag("%s should not be bss (size=%d type=%d special=%d)", s->name, (int)s->np, s->type, s->special); - put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype); - continue; - - case SFILE: - put(nil, s->name, 'f', s->value, 0, s->version, 0); - continue; - } - } - - for(s = ctxt->textp; s != nil; s = s->next) { - put(s, s->name, 'T', s->value, s->size, s->version, s->gotype); - - // NOTE(ality): acid can't produce a stack trace without .frame symbols - put(nil, ".frame", 'm', s->locals+thearch.ptrsize, 0, 0, 0); - - for(a=s->autom; a; a=a->link) { - // Emit a or p according to actual offset, even if label is wrong. - // This avoids negative offsets, which cannot be encoded. - if(a->name != A_AUTO && a->name != A_PARAM) - continue; - - // compute offset relative to FP - if(a->name == A_PARAM) - off = a->aoffset; - else - off = a->aoffset - thearch.ptrsize; - - // FP - if(off >= 0) { - put(nil, a->asym->name, 'p', off, 0, 0, a->gotype); - continue; - } - - // SP - if(off <= -thearch.ptrsize) { - put(nil, a->asym->name, 'a', -(off+thearch.ptrsize), 0, 0, a->gotype); - continue; - } - - // Otherwise, off is addressing the saved program counter. - // Something underhanded is going on. Say nothing. - } - } - if(debug['v'] || debug['n']) - Bprint(&bso, "%5.2f symsize = %ud\n", cputime(), symsize); - Bflush(&bso); -} - -vlong -symaddr(LSym *s) -{ - if(!s->reachable) - diag("unreachable symbol in symaddr - %s", s->name); - return s->value; -} - -void -xdefine(char *p, int t, vlong v) -{ - LSym *s; - - s = linklookup(ctxt, p, 0); - s->type = t; - s->value = v; - s->reachable = 1; - s->special = 1; -} - -vlong -datoff(vlong addr) -{ - if(addr >= segdata.vaddr) - return addr - segdata.vaddr + segdata.fileoff; - if(addr >= segtext.vaddr) - return addr - segtext.vaddr + segtext.fileoff; - diag("datoff %#llx", addr); - return 0; -} - -vlong -entryvalue(void) -{ - char *a; - LSym *s; - - a = INITENTRY; - if(*a >= '0' && *a <= '9') - return atolwhex(a); - s = linklookup(ctxt, a, 0); - if(s->type == 0) - return INITTEXT; - if(s->type != STEXT) - diag("entry not text: %s", s->name); - return s->value; -} - -static void -undefsym(LSym *s) -{ - int i; - Reloc *r; - - ctxt->cursym = s; - for(i=0; inr; i++) { - r = &s->r[i]; - if(r->sym == nil) // happens for some external ARM relocs - continue; - if(r->sym->type == Sxxx || r->sym->type == SXREF) - diag("undefined: %s", r->sym->name); - if(!r->sym->reachable) - diag("use of unreachable symbol: %s", r->sym->name); - } -} - -void -undef(void) -{ - LSym *s; - - for(s = ctxt->textp; s != nil; s = s->next) - undefsym(s); - for(s = datap; s != nil; s = s->next) - undefsym(s); - if(nerrors > 0) - errorexit(); -} - -void -callgraph(void) -{ - LSym *s; - Reloc *r; - int i; - - if(!debug['c']) - return; - - for(s = ctxt->textp; s != nil; s = s->next) { - for(i=0; inr; i++) { - r = &s->r[i]; - if(r->sym == nil) - continue; - if((r->type == R_CALL || r->type == R_CALLARM || r->type == R_CALLPOWER) && r->sym->type == STEXT) - Bprint(&bso, "%s calls %s\n", s->name, r->sym->name); - } - } -} - -void -diag(char *fmt, ...) -{ - char buf[1024], *tn, *sep; - va_list arg; - - tn = ""; - sep = ""; - if(ctxt->cursym != nil) { - tn = ctxt->cursym->name; - sep = ": "; - } - va_start(arg, fmt); - vseprint(buf, buf+sizeof(buf), fmt, arg); - va_end(arg); - print("%s%s%s\n", tn, sep, buf); - - nerrors++; - if(nerrors > 20) { - print("too many errors\n"); - errorexit(); - } -} - -void -checkgo(void) -{ - LSym *s; - Reloc *r; - int i; - int changed; - - if(!debug['C']) - return; - - // TODO(rsc,khr): Eventually we want to get to no Go-called C functions at all, - // which would simplify this logic quite a bit. - - // Mark every Go-called C function with cfunc=2, recursively. - do { - changed = 0; - for(s = ctxt->textp; s != nil; s = s->next) { - if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) { - for(i=0; inr; i++) { - r = &s->r[i]; - if(r->sym == nil) - continue; - if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) { - if(r->sym->cfunc == 1) { - changed = 1; - r->sym->cfunc = 2; - } - } - } - } - } - }while(changed); - - // Complain about Go-called C functions that can split the stack - // (that can be preempted for garbage collection or trigger a stack copy). - for(s = ctxt->textp; s != nil; s = s->next) { - if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) { - for(i=0; inr; i++) { - r = &s->r[i]; - if(r->sym == nil) - continue; - if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) { - if(s->cfunc == 0 && r->sym->cfunc == 2 && !r->sym->nosplit) - print("Go %s calls C %s\n", s->name, r->sym->name); - else if(s->cfunc == 2 && s->nosplit && !r->sym->nosplit) - print("Go calls C %s calls %s\n", s->name, r->sym->name); - } - } - } - } -} - -vlong -rnd(vlong v, vlong r) -{ - vlong c; - - if(r <= 0) - return v; - v += r - 1; - c = v % r; - if(c < 0) - c += r; - v -= c; - return v; -} diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h deleted file mode 100644 index fa4510d127..0000000000 --- a/src/cmd/ld/lib.h +++ /dev/null @@ -1,328 +0,0 @@ -// Derived from Inferno utils/6l/l.h -// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef EXTERN -#define EXTERN extern -#endif - -typedef struct Arch Arch; -struct Arch { - int thechar; - int ptrsize; - int intsize; - int regsize; - int funcalign; - int maxalign; - int minlc; - int dwarfregsp; - - char *linuxdynld; - char *freebsddynld; - char *netbsddynld; - char *openbsddynld; - char *dragonflydynld; - char *solarisdynld; - - void (*adddynlib)(char*); - void (*adddynrel)(LSym*, Reloc*); - void (*adddynsym)(Link*, LSym*); - void (*archinit)(void); - int (*archreloc)(Reloc*, LSym*, vlong*); - vlong (*archrelocvariant)(Reloc*, LSym*, vlong); - void (*asmb)(void); - int (*elfreloc1)(Reloc*, vlong); - void (*elfsetupplt)(void); - void (*gentext)(void); - int (*machoreloc1)(Reloc*, vlong); - - void (*lput)(uint32); - void (*wput)(uint16); - void (*vput)(uint64); -}; - -vlong rnd(vlong, vlong); - -EXTERN Arch thearch; -EXTERN LSym* datap; -EXTERN int debug[128]; -EXTERN char literal[32]; -EXTERN int32 lcsize; -EXTERN char* rpath; -EXTERN int32 spsize; -EXTERN LSym* symlist; -EXTERN int32 symsize; - -// Terrible but standard terminology. -// A segment describes a block of file to load into memory. -// A section further describes the pieces of that block for -// use in debuggers and such. - -enum { - MAXIO = 8192, - MINFUNC = 16, // minimum size for a function -}; - -typedef struct Segment Segment; -typedef struct Section Section; - -struct Segment -{ - uchar rwx; // permission as usual unix bits (5 = r-x etc) - uvlong vaddr; // virtual address - uvlong length; // length in memory - uvlong fileoff; // file offset - uvlong filelen; // length on disk - Section* sect; -}; - -struct Section -{ - uchar rwx; - int16 extnum; - int32 align; - char *name; - uvlong vaddr; - uvlong length; - Section *next; // in segment list - Segment *seg; - void *elfsect; - uvlong reloff; - uvlong rellen; -}; - -extern char symname[]; - -EXTERN char* INITENTRY; -EXTERN char* thestring; -EXTERN LinkArch* thelinkarch; -EXTERN char* outfile; -EXTERN int ndynexp; -EXTERN LSym** dynexp; -EXTERN int nldflag; -EXTERN char** ldflag; -EXTERN int havedynamic; -EXTERN int funcalign; -EXTERN int iscgo; -EXTERN int elfglobalsymndx; -extern int nelfsym; -EXTERN char* flag_installsuffix; -EXTERN int flag_race; -EXTERN int flag_shared; -EXTERN char* tracksym; -EXTERN char* interpreter; -EXTERN char* tmpdir; -EXTERN char* extld; -EXTERN char* extldflags; -EXTERN int debug_s; // backup old value of debug['s'] -EXTERN Link* ctxt; -EXTERN int32 HEADR; -EXTERN int32 HEADTYPE; -EXTERN int32 INITRND; -EXTERN int64 INITTEXT; -EXTERN int64 INITDAT; -EXTERN char* INITENTRY; /* entry point */ -EXTERN char* noname; -EXTERN char* paramspace; -EXTERN int nerrors; - -EXTERN int linkmode; -EXTERN int64 liveness; - -// for dynexport field of LSym -enum -{ - CgoExportDynamic = 1<<0, - CgoExportStatic = 1<<1, -}; - -EXTERN Segment segtext; -EXTERN Segment segrodata; -EXTERN Segment segdata; -EXTERN Segment segdwarf; - -typedef struct Endian Endian; -struct Endian -{ - uint16 (*e16)(uchar*); - uint32 (*e32)(uchar*); - uint64 (*e64)(uchar*); -}; - -extern Endian be, le; - -/* set by call to mywhatsys() */ -extern char* goroot; -extern char* goarch; -extern char* goos; - -/* whence for ldpkg */ -enum { - FileObj = 0, - ArchiveObj, - Pkgdef -}; - -EXTERN char* headstring; - -#pragma varargck type "Y" LSym* -#pragma varargck type "Z" char* -#pragma varargck type "i" char* - -// buffered output - -EXTERN Biobuf bso; - -EXTERN Biobuf coutbuf; -void cput(uint8); - -void Lflag(char *arg); -int Yconv(Fmt *fp); -int Zconv(Fmt *fp); -void addexport(void); -void address(void); -Section*addsection(Segment *seg, char *name, int rwx); -void addstrdata(char *name, char *value); -vlong addstring(LSym *s, char *str); -void asmelfsym(void); -void asmplan9sym(void); -uint16 be16(uchar *b); -uint32 be32(uchar *b); -uint64 be64(uchar *b); -void callgraph(void); -void checkgo(void); -void cflush(void); -void codeblk(int64 addr, int64 size); -vlong cpos(void); -void cseek(vlong p); -void cwrite(void *buf, int n); -void datblk(int64 addr, int64 size); -int datcmp(LSym *s1, LSym *s2); -vlong datoff(vlong addr); -void deadcode(void); -LSym* decodetype_arrayelem(LSym *s); -vlong decodetype_arraylen(LSym *s); -LSym* decodetype_chanelem(LSym *s); -int decodetype_funcdotdotdot(LSym *s); -int decodetype_funcincount(LSym *s); -LSym* decodetype_funcintype(LSym *s, int i); -int decodetype_funcoutcount(LSym *s); -LSym* decodetype_funcouttype(LSym *s, int i); -LSym* decodetype_gcprog(LSym *s); -uint8* decodetype_gcmask(LSym *s); -vlong decodetype_ifacemethodcount(LSym *s); -uint8 decodetype_kind(LSym *s); -uint8 decodetype_noptr(LSym *s); -uint8 decodetype_usegcprog(LSym *s); -LSym* decodetype_mapkey(LSym *s); -LSym* decodetype_mapvalue(LSym *s); -LSym* decodetype_ptrelem(LSym *s); -vlong decodetype_size(LSym *s); -int decodetype_structfieldcount(LSym *s); -char* decodetype_structfieldname(LSym *s, int i); -vlong decodetype_structfieldoffs(LSym *s, int i); -LSym* decodetype_structfieldtype(LSym *s, int i); -void dodata(void); -void dostkcheck(void); -void dostkoff(void); -void dosymtype(void); -void doversion(void); -void doweak(void); -void dynreloc(void); -void dynrelocsym(LSym *s); -vlong entryvalue(void); -void errorexit(void); -void follow(void); -void genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)); -void gentext(void); -void growdatsize(vlong *datsizep, LSym *s); -char* headstr(int v); -int headtype(char *name); -void hostlink(void); -void hostobjs(void); -int iconv(Fmt *fp); -void importcycles(void); -void linkarchinit(void); -void ldelf(Biobuf *f, char *pkg, int64 length, char *pn); -void ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 length, char *pn, char *file); -void ldmacho(Biobuf *f, char *pkg, int64 length, char *pn); -void ldobj(Biobuf *f, char *pkg, int64 length, char *pn, char *file, int whence); -void ldpe(Biobuf *f, char *pkg, int64 length, char *pn); -void ldpkg(Biobuf *f, char *pkg, int64 length, char *filename, int whence); -uint16 le16(uchar *b); -uint32 le32(uchar *b); -uint64 le64(uchar *b); -void libinit(void); -LSym* listsort(LSym *l, int (*cmp)(LSym*, LSym*), LSym** (*nextp)(LSym*)); -LSym** listnextp(LSym*); -LSym** listsubp(LSym*); -void loadinternal(char *name); -void loadlib(void); -void lputb(uint32 l); -void lputl(uint32 l); -void* mal(uint32 n); -void mark(LSym *s); -void mywhatsys(void); -void objfile(char *file, char *pkg); -void patch(void); -int pathchar(void); -void pcln(void); -void pclntab(void); -void findfunctab(void); -void putelfsectionsym(LSym* s, int shndx); -void putelfsymshndx(vlong sympos, int shndx); -void putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ); -int rbyoff(const void *va, const void *vb); -void reloc(void); -void relocsym(LSym *s); -void setheadtype(char *s); -void setinterp(char *s); -void setlinkmode(char *arg); -void span(void); -void strnput(char *s, int n); -vlong symaddr(LSym *s); -void symtab(void); -void textaddress(void); -void undef(void); -void unmal(void *v, uint32 n); -void usage(void); -void vputb(uint64 v); -int valuecmp(LSym *a, LSym *b); -void vputl(uint64 v); -void wputb(ushort w); -void wputl(ushort w); -void xdefine(char *p, int t, vlong v); -void zerosig(char *sp); -void archinit(void); -void diag(char *fmt, ...); - -void ldmain(int, char**); - -#pragma varargck argpos diag 1 - diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c deleted file mode 100644 index 6ce5c0de37..0000000000 --- a/src/cmd/ld/macho.c +++ /dev/null @@ -1,785 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Mach-O file writing -// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html - -#include -#include -#include -#include -#include "dwarf.h" -#include "lib.h" -#include "macho.h" - -static int macho64; -static MachoHdr machohdr; -static MachoLoad *load; -static MachoSeg seg[16]; -static int nload, mload, nseg, ndebug, nsect; - -enum -{ - SymKindLocal = 0, - SymKindExtdef, - SymKindUndef, - NumSymKind -}; - -static int nkind[NumSymKind]; -static LSym** sortsym; -static int nsortsym; - -// Amount of space left for adding load commands -// that refer to dynamic libraries. Because these have -// to go in the Mach-O header, we can't just pick a -// "big enough" header size. The initial header is -// one page, the non-dynamic library stuff takes -// up about 1300 bytes; we overestimate that as 2k. -static int load_budget = INITIAL_MACHO_HEADR - 2*1024; - -static void machodysymtab(void); - -void -machoinit(void) -{ - switch(thearch.thechar) { - // 64-bit architectures - case '6': - case '9': - macho64 = 1; - break; - - // 32-bit architectures - default: - break; - } -} - -MachoHdr* -getMachoHdr(void) -{ - return &machohdr; -} - -MachoLoad* -newMachoLoad(uint32 type, uint32 ndata) -{ - MachoLoad *l; - - if(nload >= mload) { - if(mload == 0) - mload = 1; - else - mload *= 2; - load = erealloc(load, mload*sizeof load[0]); - } - - if(macho64 && (ndata & 1)) - ndata++; - - l = &load[nload++]; - l->type = type; - l->ndata = ndata; - l->data = mal(ndata*4); - return l; -} - -MachoSeg* -newMachoSeg(char *name, int msect) -{ - MachoSeg *s; - - if(nseg >= nelem(seg)) { - diag("too many segs"); - errorexit(); - } - s = &seg[nseg++]; - s->name = name; - s->msect = msect; - s->sect = mal(msect*sizeof s->sect[0]); - return s; -} - -MachoSect* -newMachoSect(MachoSeg *seg, char *name, char *segname) -{ - MachoSect *s; - - if(seg->nsect >= seg->msect) { - diag("too many sects in segment %s", seg->name); - errorexit(); - } - s = &seg->sect[seg->nsect++]; - s->name = name; - s->segname = segname; - nsect++; - return s; -} - -// Generic linking code. - -static char **dylib; -static int ndylib; - -static vlong linkoff; - -int -machowrite(void) -{ - vlong o1; - int loadsize; - int i, j; - MachoSeg *s; - MachoSect *t; - MachoLoad *l; - - o1 = cpos(); - - loadsize = 4*4*ndebug; - for(i=0; insect); - strnput(s->name, 16); - thearch.vput(s->vaddr); - thearch.vput(s->vsize); - thearch.vput(s->fileoffset); - thearch.vput(s->filesize); - thearch.lput(s->prot1); - thearch.lput(s->prot2); - thearch.lput(s->nsect); - thearch.lput(s->flag); - } else { - thearch.lput(1); /* segment 32 */ - thearch.lput(56+68*s->nsect); - strnput(s->name, 16); - thearch.lput(s->vaddr); - thearch.lput(s->vsize); - thearch.lput(s->fileoffset); - thearch.lput(s->filesize); - thearch.lput(s->prot1); - thearch.lput(s->prot2); - thearch.lput(s->nsect); - thearch.lput(s->flag); - } - for(j=0; jnsect; j++) { - t = &s->sect[j]; - if(macho64) { - strnput(t->name, 16); - strnput(t->segname, 16); - thearch.vput(t->addr); - thearch.vput(t->size); - thearch.lput(t->off); - thearch.lput(t->align); - thearch.lput(t->reloc); - thearch.lput(t->nreloc); - thearch.lput(t->flag); - thearch.lput(t->res1); /* reserved */ - thearch.lput(t->res2); /* reserved */ - thearch.lput(0); /* reserved */ - } else { - strnput(t->name, 16); - strnput(t->segname, 16); - thearch.lput(t->addr); - thearch.lput(t->size); - thearch.lput(t->off); - thearch.lput(t->align); - thearch.lput(t->reloc); - thearch.lput(t->nreloc); - thearch.lput(t->flag); - thearch.lput(t->res1); /* reserved */ - thearch.lput(t->res2); /* reserved */ - } - } - } - - for(i=0; itype); - thearch.lput(4*(l->ndata+2)); - for(j=0; jndata; j++) - thearch.lput(l->data[j]); - } - - return cpos() - o1; -} - -void -domacho(void) -{ - LSym *s; - - if(debug['d']) - return; - - // empirically, string table must begin with " \x00". - s = linklookup(ctxt, ".machosymstr", 0); - s->type = SMACHOSYMSTR; - s->reachable = 1; - adduint8(ctxt, s, ' '); - adduint8(ctxt, s, '\x00'); - - s = linklookup(ctxt, ".machosymtab", 0); - s->type = SMACHOSYMTAB; - s->reachable = 1; - - if(linkmode != LinkExternal) { - s = linklookup(ctxt, ".plt", 0); // will be __symbol_stub - s->type = SMACHOPLT; - s->reachable = 1; - - s = linklookup(ctxt, ".got", 0); // will be __nl_symbol_ptr - s->type = SMACHOGOT; - s->reachable = 1; - s->align = 4; - - s = linklookup(ctxt, ".linkedit.plt", 0); // indirect table for .plt - s->type = SMACHOINDIRECTPLT; - s->reachable = 1; - - s = linklookup(ctxt, ".linkedit.got", 0); // indirect table for .got - s->type = SMACHOINDIRECTGOT; - s->reachable = 1; - } -} - -void -machoadddynlib(char *lib) -{ - // Will need to store the library name rounded up - // and 24 bytes of header metadata. If not enough - // space, grab another page of initial space at the - // beginning of the output file. - load_budget -= (strlen(lib)+7)/8*8 + 24; - if(load_budget < 0) { - HEADR += 4096; - INITTEXT += 4096; - load_budget += 4096; - } - - if(ndylib%32 == 0) - dylib = erealloc(dylib, (ndylib+32)*sizeof dylib[0]); - dylib[ndylib++] = lib; -} - -static void -machoshbits(MachoSeg *mseg, Section *sect, char *segname) -{ - MachoSect *msect; - char buf[40]; - char *p; - - snprint(buf, sizeof buf, "__%s", sect->name+1); - for(p=buf; *p; p++) - if(*p == '.') - *p = '_'; - - msect = newMachoSect(mseg, estrdup(buf), segname); - if(sect->rellen > 0) { - msect->reloc = sect->reloff; - msect->nreloc = sect->rellen / 8; - } - - while(1<align < sect->align) - msect->align++; - msect->addr = sect->vaddr; - msect->size = sect->length; - - if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) { - // data in file - if(sect->length > sect->seg->vaddr + sect->seg->filelen - sect->vaddr) - diag("macho cannot represent section %s crossing data and bss", sect->name); - msect->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr; - } else { - // zero fill - msect->off = 0; - msect->flag |= 1; - } - - if(sect->rwx & 1) - msect->flag |= 0x400; /* has instructions */ - - if(strcmp(sect->name, ".plt") == 0) { - msect->name = "__symbol_stub1"; - msect->flag = 0x80000408; /* only instructions, code, symbol stubs */ - msect->res1 = 0;//nkind[SymKindLocal]; - msect->res2 = 6; - } - - if(strcmp(sect->name, ".got") == 0) { - msect->name = "__nl_symbol_ptr"; - msect->flag = 6; /* section with nonlazy symbol pointers */ - msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ - } -} - -void -asmbmacho(void) -{ - vlong v, w; - vlong va; - int a, i; - MachoHdr *mh; - MachoSeg *ms; - MachoLoad *ml; - Section *sect; - - /* apple MACH */ - va = INITTEXT - HEADR; - mh = getMachoHdr(); - switch(thearch.thechar){ - default: - diag("unknown mach architecture"); - errorexit(); - case '5': - mh->cpu = MACHO_CPU_ARM; - mh->subcpu = MACHO_SUBCPU_ARMV7; - break; - case '6': - mh->cpu = MACHO_CPU_AMD64; - mh->subcpu = MACHO_SUBCPU_X86; - break; - case '8': - mh->cpu = MACHO_CPU_386; - mh->subcpu = MACHO_SUBCPU_X86; - break; - } - - ms = nil; - if(linkmode == LinkExternal) { - /* segment for entire file */ - ms = newMachoSeg("", 40); - ms->fileoffset = segtext.fileoff; - ms->filesize = segdata.fileoff + segdata.filelen - segtext.fileoff; - } - - /* segment for zero page */ - if(linkmode != LinkExternal) { - ms = newMachoSeg("__PAGEZERO", 0); - ms->vsize = va; - } - - /* text */ - v = rnd(HEADR+segtext.length, INITRND); - if(linkmode != LinkExternal) { - ms = newMachoSeg("__TEXT", 20); - ms->vaddr = va; - ms->vsize = v; - ms->fileoffset = 0; - ms->filesize = v; - ms->prot1 = 7; - ms->prot2 = 5; - } - - for(sect=segtext.sect; sect!=nil; sect=sect->next) - machoshbits(ms, sect, "__TEXT"); - - /* data */ - if(linkmode != LinkExternal) { - w = segdata.length; - ms = newMachoSeg("__DATA", 20); - ms->vaddr = va+v; - ms->vsize = w; - ms->fileoffset = v; - ms->filesize = segdata.filelen; - ms->prot1 = 3; - ms->prot2 = 3; - } - - for(sect=segdata.sect; sect!=nil; sect=sect->next) - machoshbits(ms, sect, "__DATA"); - - if(linkmode != LinkExternal) { - switch(thearch.thechar) { - default: - diag("unknown macho architecture"); - errorexit(); - case '5': - ml = newMachoLoad(5, 17+2); /* unix thread */ - ml->data[0] = 1; /* thread type */ - ml->data[1] = 17; /* word count */ - ml->data[2+15] = entryvalue(); /* start pc */ - break; - case '6': - ml = newMachoLoad(5, 42+2); /* unix thread */ - ml->data[0] = 4; /* thread type */ - ml->data[1] = 42; /* word count */ - ml->data[2+32] = entryvalue(); /* start pc */ - ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l - break; - case '8': - ml = newMachoLoad(5, 16+2); /* unix thread */ - ml->data[0] = 1; /* thread type */ - ml->data[1] = 16; /* word count */ - ml->data[2+10] = entryvalue(); /* start pc */ - break; - } - } - - if(!debug['d']) { - LSym *s1, *s2, *s3, *s4; - - // must match domacholink below - s1 = linklookup(ctxt, ".machosymtab", 0); - s2 = linklookup(ctxt, ".linkedit.plt", 0); - s3 = linklookup(ctxt, ".linkedit.got", 0); - s4 = linklookup(ctxt, ".machosymstr", 0); - - if(linkmode != LinkExternal) { - ms = newMachoSeg("__LINKEDIT", 0); - ms->vaddr = va+v+rnd(segdata.length, INITRND); - ms->vsize = s1->size + s2->size + s3->size + s4->size; - ms->fileoffset = linkoff; - ms->filesize = ms->vsize; - ms->prot1 = 7; - ms->prot2 = 3; - } - - ml = newMachoLoad(2, 4); /* LC_SYMTAB */ - ml->data[0] = linkoff; /* symoff */ - ml->data[1] = nsortsym; /* nsyms */ - ml->data[2] = linkoff + s1->size + s2->size + s3->size; /* stroff */ - ml->data[3] = s4->size; /* strsize */ - - machodysymtab(); - - if(linkmode != LinkExternal) { - ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */ - ml->data[0] = 12; /* offset to string */ - strcpy((char*)&ml->data[1], "/usr/lib/dyld"); - - for(i=0; idata[0] = 24; /* offset of string from beginning of load */ - ml->data[1] = 0; /* time stamp */ - ml->data[2] = 0; /* version */ - ml->data[3] = 0; /* compatibility version */ - strcpy((char*)&ml->data[4], dylib[i]); - } - } - } - - // TODO: dwarf headers go in ms too - if(!debug['s'] && linkmode != LinkExternal) - dwarfaddmachoheaders(); - - a = machowrite(); - if(a > HEADR) - diag("HEADR too small: %d > %d", a, HEADR); -} - -static int -symkind(LSym *s) -{ - if(s->type == SDYNIMPORT) - return SymKindUndef; - if(s->cgoexport) - return SymKindExtdef; - return SymKindLocal; -} - -static void -addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype) -{ - USED(name); - USED(addr); - USED(size); - USED(ver); - USED(gotype); - - if(s == nil) - return; - - switch(type) { - default: - return; - case 'D': - case 'B': - case 'T': - break; - } - - if(sortsym) { - sortsym[nsortsym] = s; - nkind[symkind(s)]++; - } - nsortsym++; -} - -static int -machoscmp(const void *p1, const void *p2) -{ - LSym *s1, *s2; - int k1, k2; - - s1 = *(LSym**)p1; - s2 = *(LSym**)p2; - - k1 = symkind(s1); - k2 = symkind(s2); - if(k1 != k2) - return k1 - k2; - - return strcmp(s1->extname, s2->extname); -} - -static void -machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) -{ - LSym *s; - - genasmsym(put); - for(s=ctxt->allsym; s; s=s->allsym) - if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) - if(s->reachable) - put(s, nil, 'D', 0, 0, 0, nil); -} - -void -machosymorder(void) -{ - int i; - - // On Mac OS X Mountain Lion, we must sort exported symbols - // So we sort them here and pre-allocate dynid for them - // See http://golang.org/issue/4029 - for(i=0; ireachable = 1; - machogenasmsym(addsym); - sortsym = mal(nsortsym * sizeof sortsym[0]); - nsortsym = 0; - machogenasmsym(addsym); - qsort(sortsym, nsortsym, sizeof sortsym[0], machoscmp); - for(i=0; idynid = i; -} - -static void -machosymtab(void) -{ - int i; - LSym *symtab, *symstr, *s, *o; - char *p; - - symtab = linklookup(ctxt, ".machosymtab", 0); - symstr = linklookup(ctxt, ".machosymstr", 0); - - for(i=0; isize); - - // Only add _ to C symbols. Go symbols have dot in the name. - if(strstr(s->extname, ".") == nil) - adduint8(ctxt, symstr, '_'); - // replace "·" as ".", because DTrace cannot handle it. - if(strstr(s->extname, "·") == nil) { - addstring(symstr, s->extname); - } else { - for(p = s->extname; *p; p++) { - if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) { - adduint8(ctxt, symstr, '.'); - p++; - } else { - adduint8(ctxt, symstr, *p); - } - } - adduint8(ctxt, symstr, '\x00'); - } - if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) { - adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol - adduint8(ctxt, symtab, 0); // no section - adduint16(ctxt, symtab, 0); // desc - adduintxx(ctxt, symtab, 0, thearch.ptrsize); // no value - } else { - if(s->cgoexport) - adduint8(ctxt, symtab, 0x0f); - else - adduint8(ctxt, symtab, 0x0e); - o = s; - while(o->outer != nil) - o = o->outer; - if(o->sect == nil) { - diag("missing section for %s", s->name); - adduint8(ctxt, symtab, 0); - } else - adduint8(ctxt, symtab, ((Section*)o->sect)->extnum); - adduint16(ctxt, symtab, 0); // desc - adduintxx(ctxt, symtab, symaddr(s), thearch.ptrsize); - } - } -} - -static void -machodysymtab(void) -{ - int n; - MachoLoad *ml; - LSym *s1, *s2, *s3; - - ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ - - n = 0; - ml->data[0] = n; /* ilocalsym */ - ml->data[1] = nkind[SymKindLocal]; /* nlocalsym */ - n += nkind[SymKindLocal]; - - ml->data[2] = n; /* iextdefsym */ - ml->data[3] = nkind[SymKindExtdef]; /* nextdefsym */ - n += nkind[SymKindExtdef]; - - ml->data[4] = n; /* iundefsym */ - ml->data[5] = nkind[SymKindUndef]; /* nundefsym */ - - ml->data[6] = 0; /* tocoffset */ - ml->data[7] = 0; /* ntoc */ - ml->data[8] = 0; /* modtaboff */ - ml->data[9] = 0; /* nmodtab */ - ml->data[10] = 0; /* extrefsymoff */ - ml->data[11] = 0; /* nextrefsyms */ - - // must match domacholink below - s1 = linklookup(ctxt, ".machosymtab", 0); - s2 = linklookup(ctxt, ".linkedit.plt", 0); - s3 = linklookup(ctxt, ".linkedit.got", 0); - ml->data[12] = linkoff + s1->size; /* indirectsymoff */ - ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */ - - ml->data[14] = 0; /* extreloff */ - ml->data[15] = 0; /* nextrel */ - ml->data[16] = 0; /* locreloff */ - ml->data[17] = 0; /* nlocrel */ -} - -vlong -domacholink(void) -{ - int size; - LSym *s1, *s2, *s3, *s4; - - machosymtab(); - - // write data that will be linkedit section - s1 = linklookup(ctxt, ".machosymtab", 0); - s2 = linklookup(ctxt, ".linkedit.plt", 0); - s3 = linklookup(ctxt, ".linkedit.got", 0); - s4 = linklookup(ctxt, ".machosymstr", 0); - - // Force the linkedit section to end on a 16-byte - // boundary. This allows pure (non-cgo) Go binaries - // to be code signed correctly. - // - // Apple's codesign_allocate (a helper utility for - // the codesign utility) can do this fine itself if - // it is run on a dynamic Mach-O binary. However, - // when it is run on a pure (non-cgo) Go binary, where - // the linkedit section is mostly empty, it fails to - // account for the extra padding that it itself adds - // when adding the LC_CODE_SIGNATURE load command - // (which must be aligned on a 16-byte boundary). - // - // By forcing the linkedit section to end on a 16-byte - // boundary, codesign_allocate will not need to apply - // any alignment padding itself, working around the - // issue. - while(s4->size%16) - adduint8(ctxt, s4, 0); - - size = s1->size + s2->size + s3->size + s4->size; - - if(size > 0) { - linkoff = rnd(HEADR+segtext.length, INITRND) + rnd(segdata.filelen, INITRND) + rnd(segdwarf.filelen, INITRND); - cseek(linkoff); - - cwrite(s1->p, s1->size); - cwrite(s2->p, s2->size); - cwrite(s3->p, s3->size); - cwrite(s4->p, s4->size); - } - - return rnd(size, INITRND); -} - - -void -machorelocsect(Section *sect, LSym *first) -{ - LSym *sym; - int32 eaddr; - int ri; - Reloc *r; - - // If main section has no bits, nothing to relocate. - if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen) - return; - - sect->reloff = cpos(); - for(sym = first; sym != nil; sym = sym->next) { - if(!sym->reachable) - continue; - if(sym->value >= sect->vaddr) - break; - } - - eaddr = sect->vaddr + sect->length; - for(; sym != nil; sym = sym->next) { - if(!sym->reachable) - continue; - if(sym->value >= eaddr) - break; - ctxt->cursym = sym; - - for(ri=0; rinr; ri++) { - r = &sym->r[ri]; - if(r->done) - continue; - if(thearch.machoreloc1(r, sym->value+r->off - sect->vaddr) < 0) - diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name); - } - } - - sect->rellen = cpos() - sect->reloff; -} - -void -machoemitreloc(void) -{ - Section *sect; - - while(cpos()&7) - cput(0); - - machorelocsect(segtext.sect, ctxt->textp); - for(sect=segtext.sect->next; sect!=nil; sect=sect->next) - machorelocsect(sect, datap); - for(sect=segdata.sect; sect!=nil; sect=sect->next) - machorelocsect(sect, datap); -} diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h deleted file mode 100644 index 32f905a2e9..0000000000 --- a/src/cmd/ld/macho.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -typedef struct MachoHdr MachoHdr; -struct MachoHdr { - uint32 cpu; - uint32 subcpu; -}; - -typedef struct MachoSect MachoSect; -struct MachoSect { - char* name; - char* segname; - uint64 addr; - uint64 size; - uint32 off; - uint32 align; - uint32 reloc; - uint32 nreloc; - uint32 flag; - uint32 res1; - uint32 res2; -}; - -typedef struct MachoSeg MachoSeg; -struct MachoSeg { - char* name; - uint64 vsize; - uint64 vaddr; - uint64 fileoffset; - uint64 filesize; - uint32 prot1; - uint32 prot2; - uint32 nsect; - uint32 msect; - MachoSect *sect; - uint32 flag; -}; - -typedef struct MachoLoad MachoLoad; -struct MachoLoad { - uint32 type; - uint32 ndata; - uint32 *data; -}; - -MachoHdr* getMachoHdr(void); -MachoSeg* newMachoSeg(char*, int); -MachoSect* newMachoSect(MachoSeg*, char*, char*); -MachoLoad* newMachoLoad(uint32, uint32); -int machowrite(void); -void machoinit(void); -void machosymorder(void); -void machoemitreloc(void); - -/* - * Total amount of space to reserve at the start of the file - * for Header, PHeaders, and SHeaders. - * May waste some. - */ -enum { - INITIAL_MACHO_HEADR = 4*1024, -}; - -enum { - MACHO_CPU_AMD64 = (1<<24)|7, - MACHO_CPU_386 = 7, - MACHO_SUBCPU_X86 = 3, - MACHO_CPU_ARM = 12, - MACHO_SUBCPU_ARM = 0, - MACHO_SUBCPU_ARMV7 = 9, - - MACHO32SYMSIZE = 12, - MACHO64SYMSIZE = 16, - - MACHO_X86_64_RELOC_UNSIGNED = 0, - MACHO_X86_64_RELOC_SIGNED = 1, - MACHO_X86_64_RELOC_BRANCH = 2, - MACHO_X86_64_RELOC_GOT_LOAD = 3, - MACHO_X86_64_RELOC_GOT = 4, - MACHO_X86_64_RELOC_SUBTRACTOR = 5, - MACHO_X86_64_RELOC_SIGNED_1 = 6, - MACHO_X86_64_RELOC_SIGNED_2 = 7, - MACHO_X86_64_RELOC_SIGNED_4 = 8, - - MACHO_ARM_RELOC_VANILLA = 0, - MACHO_ARM_RELOC_BR24 = 5, - - MACHO_GENERIC_RELOC_VANILLA = 0, - - MACHO_FAKE_GOTPCREL = 100, -}; - -void domacho(void); -vlong domacholink(void); -void asmbmacho(void); -void machoadddynlib(char*); diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c deleted file mode 100644 index adb7661301..0000000000 --- a/src/cmd/ld/pcln.c +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include -#include -#include "lib.h" -#include "../../runtime/funcdata.h" - -static void -addvarint(Pcdata *d, uint32 val) -{ - int32 n; - uint32 v; - uchar *p; - - n = 0; - for(v = val; v >= 0x80; v >>= 7) - n++; - n++; - - if(d->n + n > d->m) { - d->m = (d->n + n)*2; - d->p = erealloc(d->p, d->m); - } - - p = d->p + d->n; - for(v = val; v >= 0x80; v >>= 7) - *p++ = v | 0x80; - *p = v; - d->n += n; -} - -static int32 -addpctab(LSym *ftab, int32 off, Pcdata *d) -{ - int32 start; - - start = ftab->np; - symgrow(ctxt, ftab, start + d->n); - memmove(ftab->p + start, d->p, d->n); - - return setuint32(ctxt, ftab, off, start); -} - -static int32 -ftabaddstring(LSym *ftab, char *s) -{ - int32 n, start; - - n = strlen(s)+1; - start = ftab->np; - symgrow(ctxt, ftab, start+n+1); - strcpy((char*)ftab->p + start, s); - return start; -} - -static void -renumberfiles(Link *ctxt, LSym **files, int nfiles, Pcdata *d) -{ - int i; - LSym *f; - Pcdata out; - Pciter it; - uint32 v; - int32 oldval, newval, val, dv; - - // Give files numbers. - for(i=0; itype != SFILEPATH) { - f->value = ++ctxt->nhistfile; - f->type = SFILEPATH; - f->next = ctxt->filesyms; - ctxt->filesyms = f; - } - } - - newval = -1; - memset(&out, 0, sizeof out); - - for(pciterinit(ctxt, &it, d); !it.done; pciternext(&it)) { - // value delta - oldval = it.value; - if(oldval == -1) - val = -1; - else { - if(oldval < 0 || oldval >= nfiles) - sysfatal("bad pcdata %d", oldval); - val = files[oldval]->value; - } - dv = val - newval; - newval = val; - v = ((uint32)dv<<1) ^ (uint32)(int32)(dv>>31); - addvarint(&out, v); - - // pc delta - addvarint(&out, (it.nextpc - it.pc) / it.pcscale); - } - - // terminating value delta - addvarint(&out, 0); - - free(d->p); - *d = out; -} - -static int -container(LSym *s) -{ - // We want to generate func table entries only for the "lowest level" symbols, - // not containers of subsymbols. - if(s != nil && s->sub != nil) - return 1; - return 0; -} - -// pclntab initializes the pclntab symbol with -// runtime function and file name information. -void -pclntab(void) -{ - int32 i, nfunc, start, funcstart; - LSym *ftab, *s, *last; - int32 off, end, frameptrsize; - int64 funcdata_bytes; - Pcln *pcln; - Pciter it; - static Pcln zpcln; - - funcdata_bytes = 0; - ftab = linklookup(ctxt, "runtime.pclntab", 0); - ftab->type = SPCLNTAB; - ftab->reachable = 1; - - // See golang.org/s/go12symtab for the format. Briefly: - // 8-byte header - // nfunc [thearch.ptrsize bytes] - // function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes] - // end PC [thearch.ptrsize bytes] - // offset to file table [4 bytes] - nfunc = 0; - for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) { - if(!container(ctxt->cursym)) - nfunc++; - } - symgrow(ctxt, ftab, 8+thearch.ptrsize+nfunc*2*thearch.ptrsize+thearch.ptrsize+4); - setuint32(ctxt, ftab, 0, 0xfffffffb); - setuint8(ctxt, ftab, 6, thearch.minlc); - setuint8(ctxt, ftab, 7, thearch.ptrsize); - setuintxx(ctxt, ftab, 8, nfunc, thearch.ptrsize); - - nfunc = 0; - last = nil; - for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) { - last = ctxt->cursym; - if(container(ctxt->cursym)) - continue; - pcln = ctxt->cursym->pcln; - if(pcln == nil) - pcln = &zpcln; - - funcstart = ftab->np; - funcstart += -ftab->np & (thearch.ptrsize-1); - - setaddr(ctxt, ftab, 8+thearch.ptrsize+nfunc*2*thearch.ptrsize, ctxt->cursym); - setuintxx(ctxt, ftab, 8+thearch.ptrsize+nfunc*2*thearch.ptrsize+thearch.ptrsize, funcstart, thearch.ptrsize); - - // fixed size of struct, checked below - off = funcstart; - end = funcstart + thearch.ptrsize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*thearch.ptrsize; - if(pcln->nfuncdata > 0 && (end&(thearch.ptrsize-1))) - end += 4; - symgrow(ctxt, ftab, end); - - // entry uintptr - off = setaddr(ctxt, ftab, off, ctxt->cursym); - - // name int32 - off = setuint32(ctxt, ftab, off, ftabaddstring(ftab, ctxt->cursym->name)); - - // args int32 - // TODO: Move into funcinfo. - off = setuint32(ctxt, ftab, off, ctxt->cursym->args); - - // frame int32 - // TODO: Remove entirely. The pcsp table is more precise. - // This is only used by a fallback case during stack walking - // when a called function doesn't have argument information. - // We need to make sure everything has argument information - // and then remove this. - frameptrsize = thearch.ptrsize; - if(ctxt->cursym->leaf) - frameptrsize = 0; - off = setuint32(ctxt, ftab, off, ctxt->cursym->locals + frameptrsize); - - if(pcln != &zpcln) { - renumberfiles(ctxt, pcln->file, pcln->nfile, &pcln->pcfile); - if(0) { - // Sanity check the new numbering - for(pciterinit(ctxt, &it, &pcln->pcfile); !it.done; pciternext(&it)) { - if(it.value < 1 || it.value > ctxt->nhistfile) { - diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, ctxt->nhistfile); - errorexit(); - } - } - } - } - - // pcdata - off = addpctab(ftab, off, &pcln->pcsp); - off = addpctab(ftab, off, &pcln->pcfile); - off = addpctab(ftab, off, &pcln->pcline); - off = setuint32(ctxt, ftab, off, pcln->npcdata); - off = setuint32(ctxt, ftab, off, pcln->nfuncdata); - for(i=0; inpcdata; i++) - off = addpctab(ftab, off, &pcln->pcdata[i]); - - // funcdata, must be pointer-aligned and we're only int32-aligned. - // Missing funcdata will be 0 (nil pointer). - if(pcln->nfuncdata > 0) { - if(off&(thearch.ptrsize-1)) - off += 4; - for(i=0; infuncdata; i++) { - if(pcln->funcdata[i] == nil) - setuintxx(ctxt, ftab, off+thearch.ptrsize*i, pcln->funcdataoff[i], thearch.ptrsize); - else { - // TODO: Dedup. - funcdata_bytes += pcln->funcdata[i]->size; - setaddrplus(ctxt, ftab, off+thearch.ptrsize*i, pcln->funcdata[i], pcln->funcdataoff[i]); - } - } - off += pcln->nfuncdata*thearch.ptrsize; - } - - if(off != end) { - diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata, thearch.ptrsize); - errorexit(); - } - - nfunc++; - } - // Final entry of table is just end pc. - setaddrplus(ctxt, ftab, 8+thearch.ptrsize+nfunc*2*thearch.ptrsize, last, last->size); - - // Start file table. - start = ftab->np; - start += -ftab->np & (thearch.ptrsize-1); - setuint32(ctxt, ftab, 8+thearch.ptrsize+nfunc*2*thearch.ptrsize+thearch.ptrsize, start); - - symgrow(ctxt, ftab, start+(ctxt->nhistfile+1)*4); - setuint32(ctxt, ftab, start, ctxt->nhistfile); - for(s = ctxt->filesyms; s != nil; s = s->next) - setuint32(ctxt, ftab, start + s->value*4, ftabaddstring(ftab, s->name)); - - ftab->size = ftab->np; - - if(debug['v']) - Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes); -} - -enum { - BUCKETSIZE = 256*MINFUNC, - SUBBUCKETS = 16, - SUBBUCKETSIZE = BUCKETSIZE/SUBBUCKETS, - NOIDX = 0x7fffffff -}; - -// findfunctab generates a lookup table to quickly find the containing -// function for a pc. See src/runtime/symtab.go:findfunc for details. -void -findfunctab(void) -{ - LSym *t, *s, *e; - int32 idx, i, j, nbuckets, n, base; - vlong min, max, p, q; - int32 *indexes; - - t = linklookup(ctxt, "runtime.findfunctab", 0); - t->type = SRODATA; - t->reachable = 1; - - // find min and max address - min = ctxt->textp->value; - max = 0; - for(s = ctxt->textp; s != nil; s = s->next) - max = s->value + s->size; - - // for each subbucket, compute the minimum of all symbol indexes - // that map to that subbucket. - n = (max-min+SUBBUCKETSIZE-1)/SUBBUCKETSIZE; - indexes = (int32*)malloc(n*4); - if(indexes == nil) { - diag("out of memory"); - errorexit(); - } - for(i = 0; i < n; i++) - indexes[i] = NOIDX; - idx = 0; - for(s = ctxt->textp; s != nil; s = s->next) { - if(container(s)) - continue; - p = s->value; - e = s->next; - while(container(e)) - e = e->next; - if(e != nil) - q = e->value; - else - q = max; - - //print("%d: [%lld %lld] %s\n", idx, p, q, s->name); - for(; p < q; p += SUBBUCKETSIZE) { - i = (p - min) / SUBBUCKETSIZE; - if(indexes[i] > idx) - indexes[i] = idx; - } - i = (q - 1 - min) / SUBBUCKETSIZE; - if(indexes[i] > idx) - indexes[i] = idx; - idx++; - } - - // allocate table - nbuckets = (max-min+BUCKETSIZE-1)/BUCKETSIZE; - symgrow(ctxt, t, 4*nbuckets + n); - - // fill in table - for(i = 0; i < nbuckets; i++) { - base = indexes[i*SUBBUCKETS]; - if(base == NOIDX) - diag("hole in findfunctab"); - setuint32(ctxt, t, i*(4+SUBBUCKETS), base); - for(j = 0; j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++) { - idx = indexes[i*SUBBUCKETS+j]; - if(idx == NOIDX) - diag("hole in findfunctab"); - if(idx - base >= 256) { - diag("too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base); - } - setuint8(ctxt, t, i*(4+SUBBUCKETS)+4+j, idx-base); - } - } - free(indexes); -} diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c deleted file mode 100644 index 6c43581109..0000000000 --- a/src/cmd/ld/pe.c +++ /dev/null @@ -1,759 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// PE (Portable Executable) file writing -// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx - -#include -#include -#include -#include -#include "lib.h" -#include "pe.h" -#include "dwarf.h" - -// DOS stub that prints out -// "This program cannot be run in DOS mode." -static uchar dosstub[] = -{ - 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, - 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, - 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, - 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, - 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static LSym *rsrcsym; - -static char* strtbl; -static int strtblnextoff; -static int strtblsize; - -int32 PESECTHEADR; -int32 PEFILEHEADR; - -static int pe64; -static int pensect; -static int nextsectoff; -static int nextfileoff; -static int textsect; -static int datasect; - -static IMAGE_FILE_HEADER fh; -static IMAGE_OPTIONAL_HEADER oh; -static PE64_IMAGE_OPTIONAL_HEADER oh64; -static IMAGE_SECTION_HEADER sh[16]; -static IMAGE_DATA_DIRECTORY* dd; - -typedef struct Imp Imp; -struct Imp { - LSym* s; - uvlong off; - Imp* next; -}; - -typedef struct Dll Dll; -struct Dll { - char* name; - uvlong nameoff; - uvlong thunkoff; - Imp* ms; - Dll* next; -}; - -static Dll* dr; - -static LSym *dexport[1024]; -static int nexport; - -typedef struct COFFSym COFFSym; -struct COFFSym -{ - LSym* sym; - int strtbloff; - int sect; - vlong value; -}; - -static COFFSym* coffsym; -static int ncoffsym; - -static IMAGE_SECTION_HEADER* -addpesection(char *name, int sectsize, int filesize) -{ - IMAGE_SECTION_HEADER *h; - - if(pensect == 16) { - diag("too many sections"); - errorexit(); - } - h = &sh[pensect++]; - strncpy((char*)h->Name, name, sizeof(h->Name)); - h->VirtualSize = sectsize; - h->VirtualAddress = nextsectoff; - nextsectoff = rnd(nextsectoff+sectsize, PESECTALIGN); - h->PointerToRawData = nextfileoff; - if(filesize > 0) { - h->SizeOfRawData = rnd(filesize, PEFILEALIGN); - nextfileoff += h->SizeOfRawData; - } - return h; -} - -static void -chksectoff(IMAGE_SECTION_HEADER *h, vlong off) -{ - if(off != h->PointerToRawData) { - diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, off); - errorexit(); - } -} - -static void -chksectseg(IMAGE_SECTION_HEADER *h, Segment *s) -{ - if(s->vaddr-PEBASE != h->VirtualAddress) { - diag("%s.VirtualAddress = %#llux, want %#llux", (char *)h->Name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE)); - errorexit(); - } - if(s->fileoff != h->PointerToRawData) { - diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, (vlong)(s->fileoff)); - errorexit(); - } -} - -void -peinit(void) -{ - int32 l; - - switch(thearch.thechar) { - // 64-bit architectures - case '6': - pe64 = 1; - l = sizeof(oh64); - dd = oh64.DataDirectory; - break; - // 32-bit architectures - default: - l = sizeof(oh); - dd = oh.DataDirectory; - break; - } - - PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN); - PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN); - nextsectoff = PESECTHEADR; - nextfileoff = PEFILEHEADR; - - // some mingw libs depend on this symbol, for example, FindPESectionByName - xdefine("__image_base__", SDATA, PEBASE); - xdefine("_image_base__", SDATA, PEBASE); -} - -static void -pewrite(void) -{ - cseek(0); - cwrite(dosstub, sizeof dosstub); - strnput("PE", 4); - // TODO: This code should not assume that the - // memory representation is little-endian or - // that the structs are packed identically to - // their file representation. - cwrite(&fh, sizeof fh); - if(pe64) - cwrite(&oh64, sizeof oh64); - else - cwrite(&oh, sizeof oh); - cwrite(sh, pensect * sizeof sh[0]); -} - -static void -strput(char *s) -{ - int n; - - for(n=0; *s; n++) - cput(*s++); - cput('\x00'); - n++; - // string must be padded to even size - if(n%2) - cput('\x00'); -} - -static Dll* -initdynimport(void) -{ - Imp *m; - Dll *d; - LSym *s, *dynamic; - - dr = nil; - m = nil; - for(s = ctxt->allsym; s != nil; s = s->allsym) { - if(!s->reachable || s->type != SDYNIMPORT) - continue; - for(d = dr; d != nil; d = d->next) { - if(strcmp(d->name,s->dynimplib) == 0) { - m = mal(sizeof *m); - break; - } - } - if(d == nil) { - d = mal(sizeof *d); - d->name = s->dynimplib; - d->next = dr; - dr = d; - m = mal(sizeof *m); - } - m->s = s; - m->next = d->ms; - d->ms = m; - } - - dynamic = linklookup(ctxt, ".windynamic", 0); - dynamic->reachable = 1; - dynamic->type = SWINDOWS; - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) { - m->s->type = SWINDOWS | SSUB; - m->s->sub = dynamic->sub; - dynamic->sub = m->s; - m->s->value = dynamic->size; - dynamic->size += thearch.ptrsize; - } - dynamic->size += thearch.ptrsize; - } - - return dr; -} - -static void -addimports(IMAGE_SECTION_HEADER *datsect) -{ - IMAGE_SECTION_HEADER *isect; - uvlong n, oftbase, ftbase; - vlong startoff, endoff; - Imp *m; - Dll *d; - LSym* dynamic; - - startoff = cpos(); - dynamic = linklookup(ctxt, ".windynamic", 0); - - // skip import descriptor table (will write it later) - n = 0; - for(d = dr; d != nil; d = d->next) - n++; - cseek(startoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1)); - - // write dll names - for(d = dr; d != nil; d = d->next) { - d->nameoff = cpos() - startoff; - strput(d->name); - } - - // write function names - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) { - m->off = nextsectoff + cpos() - startoff; - wputl(0); // hint - strput(m->s->extname); - } - } - - // write OriginalFirstThunks - oftbase = cpos() - startoff; - n = cpos(); - for(d = dr; d != nil; d = d->next) { - d->thunkoff = cpos() - n; - for(m = d->ms; m != nil; m = m->next) { - if(pe64) - vputl(m->off); - else - lputl(m->off); - } - if(pe64) - vputl(0); - else - lputl(0); - } - - // add pe section and pad it at the end - n = cpos() - startoff; - isect = addpesection(".idata", n, n); - isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; - chksectoff(isect, startoff); - strnput("", isect->SizeOfRawData - n); - endoff = cpos(); - - // write FirstThunks (allocated in .data section) - ftbase = dynamic->value - datsect->VirtualAddress - PEBASE; - cseek(datsect->PointerToRawData + ftbase); - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) { - if(pe64) - vputl(m->off); - else - lputl(m->off); - } - if(pe64) - vputl(0); - else - lputl(0); - } - - // finally write import descriptor table - cseek(startoff); - for(d = dr; d != nil; d = d->next) { - lputl(isect->VirtualAddress + oftbase + d->thunkoff); - lputl(0); - lputl(0); - lputl(isect->VirtualAddress + d->nameoff); - lputl(datsect->VirtualAddress + ftbase + d->thunkoff); - } - lputl(0); //end - lputl(0); - lputl(0); - lputl(0); - lputl(0); - - // update data directory - dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize; - dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE; - dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size; - - cseek(endoff); -} - -static int -pescmp(const void *p1, const void *p2) -{ - LSym *s1, *s2; - - s1 = *(LSym**)p1; - s2 = *(LSym**)p2; - return strcmp(s1->extname, s2->extname); -} - -static void -initdynexport(void) -{ - LSym *s; - - nexport = 0; - for(s = ctxt->allsym; s != nil; s = s->allsym) { - if(!s->reachable || !(s->cgoexport & CgoExportDynamic)) - continue; - if(nexport+1 > nelem(dexport)) { - diag("pe dynexport table is full"); - errorexit(); - } - - dexport[nexport] = s; - nexport++; - } - - qsort(dexport, nexport, sizeof dexport[0], pescmp); -} - -void -addexports(void) -{ - IMAGE_SECTION_HEADER *sect; - IMAGE_EXPORT_DIRECTORY e; - int size, i, va, va_name, va_addr, va_na, v; - - size = sizeof e + 10*nexport + strlen(outfile) + 1; - for(i=0; iextname) + 1; - - if (nexport == 0) - return; - - sect = addpesection(".edata", size, size); - sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ; - chksectoff(sect, cpos()); - va = sect->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va; - dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize; - - va_name = va + sizeof e + nexport*4; - va_addr = va + sizeof e; - va_na = va + sizeof e + nexport*8; - - e.Characteristics = 0; - e.MajorVersion = 0; - e.MinorVersion = 0; - e.NumberOfFunctions = nexport; - e.NumberOfNames = nexport; - e.Name = va + sizeof e + nexport*10; // Program names. - e.Base = 1; - e.AddressOfFunctions = va_addr; - e.AddressOfNames = va_name; - e.AddressOfNameOrdinals = va_na; - // put IMAGE_EXPORT_DIRECTORY - for (i=0; ivalue - PEBASE); - // put EXPORT Name Pointer Table - v = e.Name + strlen(outfile)+1; - for(i=0; iextname)+1; - } - // put EXPORT Ordinal Table - for(i=0; iextname, strlen(dexport[i]->extname)+1); - strnput("", sect->SizeOfRawData - size); -} - -void -dope(void) -{ - LSym *rel; - - /* relocation table */ - rel = linklookup(ctxt, ".rel", 0); - rel->reachable = 1; - rel->type = SELFROSECT; - - initdynimport(); - initdynexport(); -} - -static int -strtbladd(char *name) -{ - int newsize, thisoff; - - newsize = strtblnextoff + strlen(name) + 1; - if(newsize > strtblsize) { - strtblsize = 2 * (newsize + (1<<18)); - strtbl = realloc(strtbl, strtblsize); - } - thisoff = strtblnextoff+4; // first string starts at offset=4 - strcpy(&strtbl[strtblnextoff], name); - strtblnextoff += strlen(name); - strtbl[strtblnextoff] = 0; - strtblnextoff++; - return thisoff; -} - -/* - * For more than 8 characters section names, name contains a slash (/) that is - * followed by an ASCII representation of a decimal number that is an offset into - * the string table. - * reference: pecoff_v8.docx Page 24. - * - */ -IMAGE_SECTION_HEADER* -newPEDWARFSection(char *name, vlong size) -{ - IMAGE_SECTION_HEADER *h; - char s[8]; - int off; - - if(size == 0) - return nil; - - off = strtbladd(name); - sprint(s, "/%d", off); - h = addpesection(s, size, size); - h->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_MEM_DISCARDABLE; - - return h; -} - -static void -addpesym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype) -{ - COFFSym *cs; - USED(name); - USED(addr); - USED(size); - USED(ver); - USED(gotype); - - if(s == nil) - return; - - if(s->sect == nil) - return; - - switch(type) { - default: - return; - case 'D': - case 'B': - case 'T': - break; - } - - if(coffsym) { - cs = &coffsym[ncoffsym]; - cs->sym = s; - if(strlen(s->name) > 8) - cs->strtbloff = strtbladd(s->name); - if(s->value >= segdata.vaddr) { - cs->value = s->value - segdata.vaddr; - cs->sect = datasect; - } else if(s->value >= segtext.vaddr) { - cs->value = s->value - segtext.vaddr; - cs->sect = textsect; - } else { - cs->value = 0; - cs->sect = 0; - diag("addpesym %#llx", addr); - } - } - ncoffsym++; -} - -static void -addpesymtable(void) -{ - IMAGE_SECTION_HEADER *h; - int i, size; - COFFSym *s; - - if(!debug['s']) { - genasmsym(addpesym); - coffsym = mal(ncoffsym * sizeof coffsym[0]); - ncoffsym = 0; - genasmsym(addpesym); - } - - size = strtblnextoff + 4 + 18*ncoffsym; - h = addpesection(".symtab", size, size); - h->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_MEM_DISCARDABLE; - chksectoff(h, cpos()); - fh.PointerToSymbolTable = cpos(); - fh.NumberOfSymbols = ncoffsym; - - // put COFF symbol table - for (i=0; istrtbloff == 0) - strnput(s->sym->name, 8); - else { - lputl(0); - lputl(s->strtbloff); - } - lputl(s->value); - wputl(s->sect); - wputl(0x0308); // "array of structs" - cput(2); // storage class: external - cput(0); // no aux entries - } - - // put COFF string table - lputl(strtblnextoff + 4); - for (i=0; iSizeOfRawData - size); -} - -void -setpersrc(LSym *sym) -{ - if(rsrcsym != nil) - diag("too many .rsrc sections"); - - rsrcsym = sym; -} - -void -addpersrc(void) -{ - IMAGE_SECTION_HEADER *h; - uchar *p; - uint32 val; - Reloc *r; - int ri; - - if(rsrcsym == nil) - return; - - h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size); - h->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA; - chksectoff(h, cpos()); - // relocation - for(ri=0; rinr; ri++) { - r = &rsrcsym->r[ri]; - p = rsrcsym->p + r->off; - val = h->VirtualAddress + r->add; - // 32-bit little-endian - p[0] = val; - p[1] = val>>8; - p[2] = val>>16; - p[3] = val>>24; - } - cwrite(rsrcsym->p, rsrcsym->size); - strnput("", h->SizeOfRawData - rsrcsym->size); - - // update data directory - dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize; -} - -void -asmbpe(void) -{ - IMAGE_SECTION_HEADER *t, *d; - - switch(thearch.thechar) { - default: - diag("unknown PE architecture"); - errorexit(); - case '6': - fh.Machine = IMAGE_FILE_MACHINE_AMD64; - break; - case '8': - fh.Machine = IMAGE_FILE_MACHINE_I386; - break; - } - - t = addpesection(".text", segtext.length, segtext.length); - t->Characteristics = IMAGE_SCN_CNT_CODE| - IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ; - chksectseg(t, &segtext); - textsect = pensect; - - d = addpesection(".data", segdata.length, segdata.filelen); - d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; - chksectseg(d, &segdata); - datasect = pensect; - - if(!debug['s']) - dwarfaddpeheaders(); - - cseek(nextfileoff); - addimports(d); - addexports(); - addpesymtable(); - addpersrc(); - - fh.NumberOfSections = pensect; - // Being able to produce identical output for identical input is - // much more beneficial than having build timestamp in the header. - fh.TimeDateStamp = 0; - fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED| - IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED; - if (pe64) { - fh.SizeOfOptionalHeader = sizeof(oh64); - fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; - oh64.Magic = 0x20b; // PE32+ - } else { - fh.SizeOfOptionalHeader = sizeof(oh); - fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE; - oh.Magic = 0x10b; // PE32 - oh.BaseOfData = d->VirtualAddress; - } - // Fill out both oh64 and oh. We only use one. Oh well. - oh64.MajorLinkerVersion = 3; - oh.MajorLinkerVersion = 3; - oh64.MinorLinkerVersion = 0; - oh.MinorLinkerVersion = 0; - oh64.SizeOfCode = t->SizeOfRawData; - oh.SizeOfCode = t->SizeOfRawData; - oh64.SizeOfInitializedData = d->SizeOfRawData; - oh.SizeOfInitializedData = d->SizeOfRawData; - oh64.SizeOfUninitializedData = 0; - oh.SizeOfUninitializedData = 0; - oh64.AddressOfEntryPoint = entryvalue()-PEBASE; - oh.AddressOfEntryPoint = entryvalue()-PEBASE; - oh64.BaseOfCode = t->VirtualAddress; - oh.BaseOfCode = t->VirtualAddress; - oh64.ImageBase = PEBASE; - oh.ImageBase = PEBASE; - oh64.SectionAlignment = PESECTALIGN; - oh.SectionAlignment = PESECTALIGN; - oh64.FileAlignment = PEFILEALIGN; - oh.FileAlignment = PEFILEALIGN; - oh64.MajorOperatingSystemVersion = 4; - oh.MajorOperatingSystemVersion = 4; - oh64.MinorOperatingSystemVersion = 0; - oh.MinorOperatingSystemVersion = 0; - oh64.MajorImageVersion = 1; - oh.MajorImageVersion = 1; - oh64.MinorImageVersion = 0; - oh.MinorImageVersion = 0; - oh64.MajorSubsystemVersion = 4; - oh.MajorSubsystemVersion = 4; - oh64.MinorSubsystemVersion = 0; - oh.MinorSubsystemVersion = 0; - oh64.SizeOfImage = nextsectoff; - oh.SizeOfImage = nextsectoff; - oh64.SizeOfHeaders = PEFILEHEADR; - oh.SizeOfHeaders = PEFILEHEADR; - if(strcmp(headstring, "windowsgui") == 0) { - oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; - oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; - } else { - oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; - oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; - } - - // Disable stack growth as we don't want Windows to - // fiddle with the thread stack limits, which we set - // ourselves to circumvent the stack checks in the - // Windows exception dispatcher. - // Commit size must be strictly less than reserve - // size otherwise reserve will be rounded up to a - // larger size, as verified with VMMap. - - // Go code would be OK with 64k stacks, but we need larger stacks for cgo. - // That default stack reserve size affects only the main thread, - // for other threads we specify stack size in runtime explicitly - // (runtime knows whether cgo is enabled or not). - // If you change stack reserve sizes here, - // change STACKSIZE in runtime/cgo/gcc_windows_{386,amd64}.c as well. - if(!iscgo) { - oh64.SizeOfStackReserve = 0x00010000; - oh.SizeOfStackReserve = 0x00010000; - oh64.SizeOfStackCommit = 0x0000ffff; - oh.SizeOfStackCommit = 0x0000ffff; - } else { - oh64.SizeOfStackReserve = 0x00200000; - oh.SizeOfStackReserve = 0x00100000; - // account for 2 guard pages - oh64.SizeOfStackCommit = 0x00200000 - 0x2000; - oh.SizeOfStackCommit = 0x00100000 - 0x2000; - } - oh64.SizeOfHeapReserve = 0x00100000; - oh.SizeOfHeapReserve = 0x00100000; - oh64.SizeOfHeapCommit = 0x00001000; - oh.SizeOfHeapCommit = 0x00001000; - oh64.NumberOfRvaAndSizes = 16; - oh.NumberOfRvaAndSizes = 16; - - pewrite(); -} diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h deleted file mode 100644 index 98632b0209..0000000000 --- a/src/cmd/ld/pe.h +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -typedef struct IMAGE_FILE_HEADER IMAGE_FILE_HEADER; -struct IMAGE_FILE_HEADER { - uint16 Machine; - uint16 NumberOfSections; - uint32 TimeDateStamp; - uint32 PointerToSymbolTable; - uint32 NumberOfSymbols; - uint16 SizeOfOptionalHeader; - uint16 Characteristics; -}; - -typedef struct IMAGE_DATA_DIRECTORY IMAGE_DATA_DIRECTORY; -struct IMAGE_DATA_DIRECTORY { - uint32 VirtualAddress; - uint32 Size; -}; - -typedef struct IMAGE_OPTIONAL_HEADER IMAGE_OPTIONAL_HEADER; -struct IMAGE_OPTIONAL_HEADER { - uint16 Magic; - uint8 MajorLinkerVersion; - uint8 MinorLinkerVersion; - uint32 SizeOfCode; - uint32 SizeOfInitializedData; - uint32 SizeOfUninitializedData; - uint32 AddressOfEntryPoint; - uint32 BaseOfCode; - uint32 BaseOfData; - uint32 ImageBase; - uint32 SectionAlignment; - uint32 FileAlignment; - uint16 MajorOperatingSystemVersion; - uint16 MinorOperatingSystemVersion; - uint16 MajorImageVersion; - uint16 MinorImageVersion; - uint16 MajorSubsystemVersion; - uint16 MinorSubsystemVersion; - uint32 Win32VersionValue; - uint32 SizeOfImage; - uint32 SizeOfHeaders; - uint32 CheckSum; - uint16 Subsystem; - uint16 DllCharacteristics; - uint32 SizeOfStackReserve; - uint32 SizeOfStackCommit; - uint32 SizeOfHeapReserve; - uint32 SizeOfHeapCommit; - uint32 LoaderFlags; - uint32 NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[16]; -}; - -typedef struct IMAGE_SECTION_HEADER IMAGE_SECTION_HEADER; -struct IMAGE_SECTION_HEADER { - uint8 Name[8]; - uint32 VirtualSize; - uint32 VirtualAddress; - uint32 SizeOfRawData; - uint32 PointerToRawData; - uint32 PointerToRelocations; - uint32 PointerToLineNumbers; - uint16 NumberOfRelocations; - uint16 NumberOfLineNumbers; - uint32 Characteristics; -}; - -typedef struct IMAGE_IMPORT_DESCRIPTOR IMAGE_IMPORT_DESCRIPTOR; -struct IMAGE_IMPORT_DESCRIPTOR { - uint32 OriginalFirstThunk; - uint32 TimeDateStamp; - uint32 ForwarderChain; - uint32 Name; - uint32 FirstThunk; -}; - -typedef struct IMAGE_EXPORT_DIRECTORY IMAGE_EXPORT_DIRECTORY; -struct IMAGE_EXPORT_DIRECTORY { - uint32 Characteristics; - uint32 TimeDateStamp; - uint16 MajorVersion; - uint16 MinorVersion; - uint32 Name; - uint32 Base; - uint32 NumberOfFunctions; - uint32 NumberOfNames; - uint32 AddressOfFunctions; - uint32 AddressOfNames; - uint32 AddressOfNameOrdinals; -}; - -enum { - PEBASE = 0x00400000, -// SectionAlignment must be greater than or equal to FileAlignment. -// The default is the page size for the architecture. - PESECTALIGN = 0x1000, -// FileAlignment should be a power of 2 between 512 and 64 K, inclusive. -// The default is 512. If the SectionAlignment is less than -// the architecture's page size, then FileAlignment must match SectionAlignment. - PEFILEALIGN = (2<<8), -}; - -extern int32 PESECTHEADR; -extern int32 PEFILEHEADR; - -enum { - IMAGE_FILE_MACHINE_I386 = 0x14c, - IMAGE_FILE_MACHINE_AMD64 = 0x8664, - - IMAGE_FILE_RELOCS_STRIPPED = 0x0001, - IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002, - IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020, - IMAGE_FILE_32BIT_MACHINE = 0x0100, - IMAGE_FILE_DEBUG_STRIPPED = 0x0200, - - IMAGE_SCN_CNT_CODE = 0x00000020, - IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040, - IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080, - IMAGE_SCN_MEM_EXECUTE = 0x20000000, - IMAGE_SCN_MEM_READ = 0x40000000, - IMAGE_SCN_MEM_WRITE = 0x80000000, - IMAGE_SCN_MEM_DISCARDABLE = 0x2000000, - - IMAGE_DIRECTORY_ENTRY_EXPORT = 0, - IMAGE_DIRECTORY_ENTRY_IMPORT = 1, - IMAGE_DIRECTORY_ENTRY_RESOURCE = 2, - IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3, - IMAGE_DIRECTORY_ENTRY_SECURITY = 4, - IMAGE_DIRECTORY_ENTRY_BASERELOC = 5, - IMAGE_DIRECTORY_ENTRY_DEBUG = 6, - IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7, - IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7, - IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8, - IMAGE_DIRECTORY_ENTRY_TLS = 9, - IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10, - IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11, - IMAGE_DIRECTORY_ENTRY_IAT = 12, - IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13, - IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14, - - IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, - IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, -}; - -void peinit(void); -void asmbpe(void); -void dope(void); - -IMAGE_SECTION_HEADER* newPEDWARFSection(char *name, vlong size); - -// X64 -typedef struct PE64_IMAGE_OPTIONAL_HEADER PE64_IMAGE_OPTIONAL_HEADER; -struct PE64_IMAGE_OPTIONAL_HEADER { - uint16 Magic; - uint8 MajorLinkerVersion; - uint8 MinorLinkerVersion; - uint32 SizeOfCode; - uint32 SizeOfInitializedData; - uint32 SizeOfUninitializedData; - uint32 AddressOfEntryPoint; - uint32 BaseOfCode; - uint64 ImageBase; - uint32 SectionAlignment; - uint32 FileAlignment; - uint16 MajorOperatingSystemVersion; - uint16 MinorOperatingSystemVersion; - uint16 MajorImageVersion; - uint16 MinorImageVersion; - uint16 MajorSubsystemVersion; - uint16 MinorSubsystemVersion; - uint32 Win32VersionValue; - uint32 SizeOfImage; - uint32 SizeOfHeaders; - uint32 CheckSum; - uint16 Subsystem; - uint16 DllCharacteristics; - uint64 SizeOfStackReserve; - uint64 SizeOfStackCommit; - uint64 SizeOfHeapReserve; - uint64 SizeOfHeapCommit; - uint32 LoaderFlags; - uint32 NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[16]; -}; - -void setpersrc(LSym *sym); diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c deleted file mode 100644 index f3bab30a50..0000000000 --- a/src/cmd/ld/pobj.c +++ /dev/null @@ -1,198 +0,0 @@ -// Inferno utils/6l/obj.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Reading object files. - -#define EXTERN -#include -#include -#include -#include -#include "lib.h" -#include "elf.h" -#include "macho.h" -#include "dwarf.h" -#include "pe.h" -#include - -char *noname = ""; -char* paramspace = "FP"; - -void -ldmain(int argc, char **argv) -{ - int i; - - ctxt = linknew(thelinkarch); - ctxt->thechar = thearch.thechar; - ctxt->thestring = thestring; - ctxt->diag = diag; - ctxt->bso = &bso; - - Binit(&bso, 1, OWRITE); - memset(debug, 0, sizeof(debug)); - nerrors = 0; - outfile = nil; - HEADTYPE = -1; - INITTEXT = -1; - INITDAT = -1; - INITRND = -1; - INITENTRY = 0; - linkmode = LinkAuto; - - // For testing behavior of go command when tools crash. - // Undocumented, not in standard flag parser to avoid - // exposing in usage message. - for(i=1; igoarm == 5) - debug['F'] = 1; - - flagcount("1", "use alternate profiling code", &debug['1']); - if(thearch.thechar == '6') - flagcount("8", "assume 64-bit addresses", &debug['8']); - flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); - flagcount("C", "check Go calls to C code", &debug['C']); - flagint64("D", "addr: data address", &INITDAT); - flagstr("E", "sym: entry symbol", &INITENTRY); - if(thearch.thechar == '5') - flagcount("G", "debug pseudo-ops", &debug['G']); - flagfn1("I", "interp: set ELF interp", setinterp); - flagfn1("L", "dir: add dir to library path", Lflag); - flagfn1("H", "head: header type", setheadtype); - flagcount("K", "add stack underflow checks", &debug['K']); - if(thearch.thechar == '5') - flagcount("M", "disable software div/mod", &debug['M']); - flagcount("O", "print pc-line tables", &debug['O']); - flagcount("Q", "debug byte-register code gen", &debug['Q']); - if(thearch.thechar == '5') - flagcount("P", "debug code generation", &debug['P']); - flagint32("R", "rnd: address rounding", &INITRND); - flagcount("nil", "check type signatures", &debug['S']); - flagint64("T", "addr: text address", &INITTEXT); - flagfn0("V", "print version and exit", doversion); - flagcount("W", "disassemble input", &debug['W']); - flagfn2("X", "name value: define string data", addstrdata); - flagcount("Z", "clear stack frame on entry", &debug['Z']); - flagcount("a", "disassemble output", &debug['a']); - flagcount("c", "dump call graph", &debug['c']); - flagcount("d", "disable dynamic executable", &debug['d']); - flagstr("extld", "ld: linker to run in external mode", &extld); - flagstr("extldflags", "ldflags: flags for external linker", &extldflags); - flagcount("f", "ignore version mismatch", &debug['f']); - flagcount("g", "disable go package data checks", &debug['g']); - flagstr("installsuffix", "suffix: pkg directory suffix", &flag_installsuffix); - flagstr("k", "sym: set field tracking symbol", &tracksym); - flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); - flagcount("n", "dump symbol table", &debug['n']); - flagstr("o", "outfile: set output file", &outfile); - flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); - flagcount("race", "enable race detector", &flag_race); - flagcount("s", "disable symbol table", &debug['s']); - if(thearch.thechar == '5' || thearch.thechar == '6') - flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared); - flagstr("tmpdir", "dir: leave temporary files in this directory", &tmpdir); - flagcount("u", "reject unsafe packages", &debug['u']); - flagcount("v", "print link trace", &debug['v']); - flagcount("w", "disable DWARF generation", &debug['w']); - - flagparse(&argc, &argv, usage); - ctxt->bso = &bso; - ctxt->debugvlog = debug['v']; - - if(argc != 1) - usage(); - - if(outfile == nil) { - if(HEADTYPE == Hwindows) - outfile = smprint("%c.out.exe", thearch.thechar); - else - outfile = smprint("%c.out", thearch.thechar); - } - libinit(); // creates outfile - - if(HEADTYPE == -1) - HEADTYPE = headtype(goos); - ctxt->headtype = HEADTYPE; - if(headstring == nil) - headstring = headstr(HEADTYPE); - - thearch.archinit(); - - if(debug['v']) - Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n", - HEADTYPE, INITTEXT, INITDAT, INITRND); - Bflush(&bso); - - addlibpath(ctxt, "command line", "command line", argv[0], "main"); - loadlib(); - - if(thearch.thechar == '5') { - // mark some functions that are only referenced after linker code editing - if(debug['F']) - mark(linkrlookup(ctxt, "_sfloat", 0)); - mark(linklookup(ctxt, "runtime.read_tls_fallback", 0)); - } - - checkgo(); - deadcode(); - callgraph(); - paramspace = "SP"; /* (FP) now (SP) on output */ - - doelf(); - if(HEADTYPE == Hdarwin) - domacho(); - dostkcheck(); - if(HEADTYPE == Hwindows) - dope(); - addexport(); - thearch.gentext(); // trampolines, call stubs, etc. - textaddress(); - pclntab(); - findfunctab(); - symtab(); - dodata(); - address(); - doweak(); - reloc(); - thearch.asmb(); - undef(); - hostlink(); - if(debug['v']) { - Bprint(&bso, "%5.2f cpu time\n", cputime()); - Bprint(&bso, "%d symbols\n", ctxt->nsymbol); - Bprint(&bso, "%lld liveness data\n", liveness); - } - Bflush(&bso); - - errorexit(); -} diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c deleted file mode 100644 index 34aa1cc336..0000000000 --- a/src/cmd/ld/symtab.c +++ /dev/null @@ -1,449 +0,0 @@ -// Inferno utils/6l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Symbol table. - -#include -#include -#include -#include -#include "lib.h" -#include "elf.h" -#include "dwarf.h" - -static int maxelfstr; - -static int -putelfstr(char *s) -{ - int off, n; - char *p, *q; - - if(elfstrsize == 0 && s[0] != 0) { - // first entry must be empty string - putelfstr(""); - } - - n = strlen(s)+1; - if(elfstrsize+n > maxelfstr) { - maxelfstr = 2*(elfstrsize+n+(1<<20)); - elfstrdat = realloc(elfstrdat, maxelfstr); - } - off = elfstrsize; - elfstrsize += n; - memmove(elfstrdat+off, s, n); - // replace "·" as ".", because DTrace cannot handle it. - p = strstr(s, "·"); - if(p != nil) { - p = q = elfstrdat+off; - while (*q != '\x00') { - if((uchar)*q == 0xc2 && (uchar)*(q+1) == 0xb7) { - q += 2; - *p++ = '.'; - elfstrsize--; - } else { - *p++ = *q++; - } - } - *p = '\x00'; - } - return off; -} - -static void -putelfsyment(int off, vlong addr, vlong size, int info, int shndx, int other) -{ - switch(thearch.thechar) { - case '6': - case '9': - thearch.lput(off); - cput(info); - cput(other); - thearch.wput(shndx); - thearch.vput(addr); - thearch.vput(size); - symsize += ELF64SYMSIZE; - break; - default: - thearch.lput(off); - thearch.lput(addr); - thearch.lput(size); - cput(info); - cput(other); - thearch.wput(shndx); - symsize += ELF32SYMSIZE; - break; - } -} - -static int numelfsym = 1; // 0 is reserved -static int elfbind; - -static void -putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go) -{ - int bind, type, off, other; - LSym *xo; - - USED(go); - switch(t) { - default: - return; - case 'T': - type = STT_FUNC; - break; - case 'D': - type = STT_OBJECT; - break; - case 'B': - type = STT_OBJECT; - break; - } - xo = x; - while(xo->outer != nil) - xo = xo->outer; - if(xo->sect == nil) { - ctxt->cursym = x; - diag("missing section in putelfsym"); - return; - } - if(((Section*)xo->sect)->elfsect == nil) { - ctxt->cursym = x; - diag("missing ELF section in putelfsym"); - return; - } - - // One pass for each binding: STB_LOCAL, STB_GLOBAL, - // maybe one day STB_WEAK. - bind = STB_GLOBAL; - if(ver || (x->type & SHIDDEN)) - bind = STB_LOCAL; - - // In external linking mode, we have to invoke gcc with -rdynamic - // to get the exported symbols put into the dynamic symbol table. - // To avoid filling the dynamic table with lots of unnecessary symbols, - // mark all Go symbols local (not global) in the final executable. - if(linkmode == LinkExternal && !(x->cgoexport&CgoExportStatic)) - bind = STB_LOCAL; - - if(bind != elfbind) - return; - - off = putelfstr(s); - if(linkmode == LinkExternal) - addr -= ((Section*)xo->sect)->vaddr; - other = 2; - if(x->type&SHIDDEN) - other = 0; - putelfsyment(off, addr, size, (bind<<4)|(type&0xf), ((ElfShdr*)((Section*)xo->sect)->elfsect)->shnum, other); - x->elfsym = numelfsym++; -} - -void -putelfsectionsym(LSym* s, int shndx) -{ - putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0); - s->elfsym = numelfsym++; -} - -void -putelfsymshndx(vlong sympos, int shndx) -{ - vlong here; - - here = cpos(); - switch(thearch.thechar) { - case '6': - cseek(sympos+6); - break; - default: - cseek(sympos+14); - break; - } - thearch.wput(shndx); - cseek(here); -} - -void -asmelfsym(void) -{ - LSym *s; - char *name; - - // the first symbol entry is reserved - putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0); - - dwarfaddelfsectionsyms(); - - elfbind = STB_LOCAL; - genasmsym(putelfsym); - - if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) { - s = linklookup(ctxt, "runtime.tlsg", 0); - if(s->sect == nil) { - ctxt->cursym = nil; - diag("missing section for %s", s->name); - errorexit(); - } - if (strcmp(goos, "android") == 0) { - // Android emulates runtime.tlsg as a regular variable. - putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_OBJECT, ((ElfShdr*)((Section*)s->sect)->elfsect)->shnum, 0); - } else { - putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_TLS, ((ElfShdr*)((Section*)s->sect)->elfsect)->shnum, 0); - } - s->elfsym = numelfsym++; - } - - elfbind = STB_GLOBAL; - elfglobalsymndx = numelfsym; - genasmsym(putelfsym); - - for(s=ctxt->allsym; s!=nil; s=s->allsym) { - if(s->type != SHOSTOBJ && !(s->type == SDYNIMPORT && s->reachable)) - continue; - if(s->type == SDYNIMPORT) - name = s->extname; - else - name = s->name; - putelfsyment(putelfstr(name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0); - s->elfsym = numelfsym++; - } -} - -static void -putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go) -{ - int i, l; - - USED(go); - USED(ver); - USED(size); - USED(x); - switch(t) { - case 'T': - case 'L': - case 'D': - case 'B': - if(ver) - t += 'a' - 'A'; - case 'a': - case 'p': - case 'f': - case 'z': - case 'Z': - case 'm': - l = 4; - if(HEADTYPE == Hplan9 && thearch.thechar == '6' && !debug['8']) { - lputb(addr>>32); - l = 8; - } - lputb(addr); - cput(t+0x80); /* 0x80 is variable length */ - - if(t == 'z' || t == 'Z') { - cput(s[0]); - for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { - cput(s[i]); - cput(s[i+1]); - } - cput(0); - cput(0); - i++; - } else { - /* skip the '<' in filenames */ - if(t == 'f') - s++; - for(i=0; s[i]; i++) - cput(s[i]); - cput(0); - } - symsize += l + 1 + i + 1; - break; - default: - return; - }; -} - -void -asmplan9sym(void) -{ - genasmsym(putplan9sym); -} - -static LSym *symt; - -void -wputl(ushort w) -{ - cput(w); - cput(w>>8); -} - -void -wputb(ushort w) -{ - cput(w>>8); - cput(w); -} - -void -lputb(uint32 l) -{ - cput(l>>24); - cput(l>>16); - cput(l>>8); - cput(l); -} - -void -lputl(uint32 l) -{ - cput(l); - cput(l>>8); - cput(l>>16); - cput(l>>24); -} - -void -vputb(uint64 v) -{ - lputb(v>>32); - lputb(v); -} - -void -vputl(uint64 v) -{ - lputl(v); - lputl(v >> 32); -} - -void -symtab(void) -{ - LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc; - - dosymtype(); - - // Define these so that they'll get put into the symbol table. - // data.c:/^address will provide the actual values. - xdefine("runtime.text", STEXT, 0); - xdefine("runtime.etext", STEXT, 0); - xdefine("runtime.typelink", SRODATA, 0); - xdefine("runtime.etypelink", SRODATA, 0); - xdefine("runtime.rodata", SRODATA, 0); - xdefine("runtime.erodata", SRODATA, 0); - xdefine("runtime.noptrdata", SNOPTRDATA, 0); - xdefine("runtime.enoptrdata", SNOPTRDATA, 0); - xdefine("runtime.data", SDATA, 0); - xdefine("runtime.edata", SDATA, 0); - xdefine("runtime.bss", SBSS, 0); - xdefine("runtime.ebss", SBSS, 0); - xdefine("runtime.noptrbss", SNOPTRBSS, 0); - xdefine("runtime.enoptrbss", SNOPTRBSS, 0); - xdefine("runtime.end", SBSS, 0); - xdefine("runtime.epclntab", SRODATA, 0); - xdefine("runtime.esymtab", SRODATA, 0); - - // garbage collection symbols - s = linklookup(ctxt, "runtime.gcdata", 0); - s->type = SRODATA; - s->size = 0; - s->reachable = 1; - xdefine("runtime.egcdata", SRODATA, 0); - - s = linklookup(ctxt, "runtime.gcbss", 0); - s->type = SRODATA; - s->size = 0; - s->reachable = 1; - xdefine("runtime.egcbss", SRODATA, 0); - - // pseudo-symbols to mark locations of type, string, and go string data. - s = linklookup(ctxt, "type.*", 0); - s->type = STYPE; - s->size = 0; - s->reachable = 1; - symtype = s; - - s = linklookup(ctxt, "go.string.*", 0); - s->type = SGOSTRING; - s->size = 0; - s->reachable = 1; - symgostring = s; - - s = linklookup(ctxt, "go.func.*", 0); - s->type = SGOFUNC; - s->size = 0; - s->reachable = 1; - symgofunc = s; - - symtypelink = linklookup(ctxt, "runtime.typelink", 0); - - symt = linklookup(ctxt, "runtime.symtab", 0); - symt->type = SSYMTAB; - symt->size = 0; - symt->reachable = 1; - - // assign specific types so that they sort together. - // within a type they sort by size, so the .* symbols - // just defined above will be first. - // hide the specific symbols. - for(s = ctxt->allsym; s != nil; s = s->allsym) { - if(!s->reachable || s->special || s->type != SRODATA) - continue; - if(strncmp(s->name, "type.", 5) == 0) { - s->type = STYPE; - s->hide = 1; - s->outer = symtype; - } - if(strncmp(s->name, "go.typelink.", 12) == 0) { - s->type = STYPELINK; - s->hide = 1; - s->outer = symtypelink; - } - if(strncmp(s->name, "go.string.", 10) == 0) { - s->type = SGOSTRING; - s->hide = 1; - s->outer = symgostring; - } - if(strncmp(s->name, "go.func.", 8) == 0) { - s->type = SGOFUNC; - s->hide = 1; - s->outer = symgofunc; - } - if(strncmp(s->name, "gcargs.", 7) == 0 || strncmp(s->name, "gclocals.", 9) == 0 || strncmp(s->name, "gclocals·", 10) == 0) { - s->type = SGOFUNC; - s->hide = 1; - s->outer = symgofunc; - s->align = 4; - liveness += (s->size+s->align-1)&~(s->align-1); - } - } -} diff --git a/src/cmd/ld/textflag.h b/src/runtime/textflag.h similarity index 87% rename from src/cmd/ld/textflag.h rename to src/runtime/textflag.h index 0ee8b5f1ce..2a76e76c29 100644 --- a/src/cmd/ld/textflag.h +++ b/src/runtime/textflag.h @@ -21,16 +21,3 @@ #define WRAPPER 32 // This function uses its incoming context register. #define NEEDCTXT 64 - -/*c2go -enum -{ - NOPROF = 1, - DUPOK = 2, - NOSPLIT = 4, - RODATA = 8, - NOPTR = 16, - WRAPPER = 32, - NEEDCTXT = 64, -}; -*/ -- 2.48.1