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 <r@golang.org>
+++ /dev/null
-# 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
+++ /dev/null
-// 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);
- }
-}
+++ /dev/null
-// 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
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-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
-};
+++ /dev/null
-// 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 <ar.h>
-
-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);
-}
+++ /dev/null
-# 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
+++ /dev/null
-// 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();
-}
+++ /dev/null
-// 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
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-#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
-};
+++ /dev/null
-// 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 <ar.h>
-
-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);
-}
+++ /dev/null
-# 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
+++ /dev/null
-// 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();
-}
+++ /dev/null
-// 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
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-#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
-};
+++ /dev/null
-// 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 <ar.h>
-
-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);
-}
+++ /dev/null
-# 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
+++ /dev/null
-// 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; r<s->r+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);
- }
-}
+++ /dev/null
-// 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
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-#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
-};
+++ /dev/null
-// 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 <ar.h>
-
-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);
-}
}
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"+
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",
}},
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.
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)
}
// 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",
var bootstrapDirs = []string{
"5a",
"5g",
+ "5l",
"6a",
"6g",
+ "6l",
"8a",
"8g",
+ "8l",
"9a",
"9g",
+ "9l",
"asm",
"asm/internal/arch",
"asm/internal/asm",
"internal/obj/i386",
"internal/obj/ppc64",
"internal/obj/x86",
- "new5l",
- "new6l",
- "new8l",
- "new9l",
}
func bootstrapBuildTools() {
}
}
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 {
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,
"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,
+++ /dev/null
-# 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
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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; ri<s->nr; 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 : "<nil>", (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; ri<s->nr; 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; ri<s->nr; 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; i<sym->nr; 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);
-}
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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);
-}
+++ /dev/null
-// 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
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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; j<nelem(abbrevs[i].attr); j++) {
- f = &abbrevs[i].attr[j];
- uleb128put(f->attr);
- 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<value; i++)
- cput(p[i]);
- break;
-
- case DW_FORM_block2: // block
- value &= 0xffff;
- thearch.wput(value);
- p = data;
- for(i=0; i<value; i++)
- cput(p[i]);
- break;
-
- case DW_FORM_block4: // block
- value &= 0xffffffff;
- thearch.lput(value);
- p = data;
- for(i=0; i<value; i++)
- cput(p[i]);
- break;
-
- case DW_FORM_block: // block
- uleb128put(value);
- p = data;
- for(i=0; i<value; i++)
- cput(p[i]);
- break;
-
- case DW_FORM_data1: // constant
- cput(value);
- break;
-
- case DW_FORM_data2: // constant
- thearch.wput(value);
- break;
-
- case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
- if(linkmode == LinkExternal && cls == DW_CLS_PTR) {
- adddwarfrel(infosec, linesym, infoo, 4, value);
- break;
- }
- thearch.lput(value);
- break;
-
- case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
- thearch.vput(value);
- break;
-
- case DW_FORM_sdata: // constant
- sleb128put(value);
- break;
-
- case DW_FORM_udata: // constant
- uleb128put(value);
- break;
-
- case DW_FORM_string: // string
- strnput(data, value+1);
- break;
-
- case DW_FORM_flag: // flag
- if(value) {
- cput(1);
- }else{
- cput(0);
- }
- break;
-
- case DW_FORM_ref_addr: // reference to a DIE in the .info section
- // In DWARF 2 (which is what we claim to generate),
- // the ref_addr is the same size as a normal address.
- // In DWARF 3 it is always 32 bits, unless emitting a large
- // (> 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, "<unspecified>");
-
- if (strncmp("type.", gotype->name, 5) != 0) {
- diag("dwarf: type name doesn't start with \".type\": %s", gotype->name);
- return find_or_diag(&dwtypes, "<unspecified>");
- }
- 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, "<unspecified>"));
- }
-
- 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<K,V>
- 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<K,V>
- 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<K,V>
- 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<T>
- 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<T>
- 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<T>
- 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; i<s->pcln->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; i<ctxt->nhistfile; 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; ri<s->nr; 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, "<unspecified>");
- 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);
-}
+++ /dev/null
-// 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);
+++ /dev/null
-// 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
-};
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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; i<nbucket; i++)
- adduint32(ctxt, s, buckets[i]);
- for(i = 0; i<nsym; i++)
- adduint32(ctxt, s, chain[i]);
-
- free(chain);
- free(buckets);
-
- // version symbols
- dynstr = linklookup(ctxt, ".dynstr", 0);
- s = linklookup(ctxt, ".gnu.version_r", 0);
- i = 2;
- nfile = 0;
- for(l=needlib; l; l=l->next) {
- 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; i<nsym; i++) {
- if(i == 0)
- adduint16(ctxt, s, 0); // first entry - no symbol
- else if(need[i] == nil)
- adduint16(ctxt, s, 1); // global
- else
- adduint16(ctxt, s, need[i]->num);
- }
-
- 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; i<nelfstr; i++) {
- if(strcmp(name, elfstr[i].s) == 0) {
- off = elfstr[i].off;
- goto found;
- }
- }
- diag("cannot find elf name %s", name);
- errorexit();
- return nil;
-
-found:
- for(i=0; i<ehdr.shnum; i++) {
- sh = shdr[i];
- if(sh->name == 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; ri<sym->nr; 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;
-}
+++ /dev/null
-/*
- * 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,
-};
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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<pend; p=next) {
- next = strchr(p, '\n');
- if(next == nil)
- next = "";
- else
- *next++ = '\x00';
-
- free(p0);
- p0 = estrdup(p); // save for error message
- nf = tokenize(p, f, nelem(f));
-
- if(strcmp(f[0], "cgo_import_dynamic") == 0) {
- if(nf < 2 || nf > 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; i<s->nr; i++)
- mark1(s->r[i].sym, s);
- if(s->pcln) {
- for(i=0; i<s->pcln->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; i<nelem(markextra); i++)
- mark(linklookup(ctxt, markextra[i], 0));
-
- for(i=0; i<ndynexp; i++)
- mark(dynexp[i]);
-
- markflood();
-
- // keep each beginning with 'typelink.' if the symbol it points at is being kept.
- for(s = ctxt->allsym; 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; i<ndynexp; i++)
- thearch.adddynsym(ctxt, dynexp[i]);
-}
-
-/* %Z from gc, for quoting import paths */
-int
-Zconv(Fmt *fp)
-{
- Rune r;
- char *s, *se;
- int n;
-
- s = va_arg(fp->args, char*);
- if(s == nil)
- return fmtstrcpy(fp, "<nil>");
-
- 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; i<p->nimpby; 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();
- }
-}
+++ /dev/null
-/*
-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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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; i<elfobj->nsect; 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; i<elfobj->nsect; 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; i<elfobj->nsect; 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; i<elfobj->nsymtab; 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; i<elfobj->nsect; 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; i<elfobj->nsect; 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; j<n; j++) {
- add = 0;
- rp = &r[j];
- if(is64) {
- // 64-bit rel/rela
- rp->off = 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; i<elfobj->nsect; 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;
-}
+++ /dev/null
-/*
-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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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; i<c->seg.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; i<c->seg.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; i<sect->nreloc; 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; i<n; i++)
- d->indir[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; i<symtab->nsym; 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; i<ncmd; i++){
- ty = e->e32(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; i<c->seg.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; i<symtab->nsym; 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; i<c->seg.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; i<c->seg.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; j<sect->nreloc; 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; k<c->seg.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);
-}
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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; i<peobj->fh.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; i<peobj->nsect; 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; i<peobj->nsect; 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; j<rsect->sh.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; i<peobj->npesym; 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; i<peobj->nsect; 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;
-}
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "lib.h"
-#include "elf.h"
-#include "dwarf.h"
-#include "../../runtime/stack.h"
-#include "../../runtime/funcdata.h"
-
-#include <ar.h>
-#if !(defined(_WIN32) || defined(PLAN9))
-#include <sys/stat.h>
-#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; i<ctxt->nlibdir; 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; i<ctxt->libraryp; 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; i<ndynexp; i++)
- if(dynexp[i]->cgoexport & 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<nelem(internalpkg); i++) {
- if(strcmp(pkg, internalpkg[i]) == 0) {
- isinternal = 1;
- break;
- }
- }
-
- // DragonFly declares errno with __thread, which results in a symbol
- // type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
- // currently know how to handle TLS relocations, hence we have to
- // force external linking for any libraries that link in code that
- // uses errno. This can be removed if the Go linker ever supports
- // these relocation types.
- if(HEADTYPE == Hdragonfly)
- if(strcmp(pkg, "net") == 0 || strcmp(pkg, "os/user") == 0)
- isinternal = 0;
-
- if(!isinternal)
- externalobj = 1;
-
- if(nhostobj >= 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; i<nhostobj; i++) {
- h = &hostobj[i];
- f = Bopen(h->file, 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; i<nhostobj; i++) {
- h = &hostobj[i];
- f = Bopen(h->file, 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; i<nldflag; i++)
- argv[argc++] = ldflag[i];
-
- p = extldflags;
- while(p != nil) {
- while(*p == ' ')
- *p++ = '\x00';
- if(*p == '\x00')
- break;
- argv[argc++] = p;
-
- // clang, unlike GCC, passes -rdynamic to the linker
- // even when linking with -static, causing a linker
- // error when using GNU ld. So take out -rdynamic if
- // we added it. We do it in this order, rather than
- // only adding -rdynamic later, so that -extldflags
- // can override -rdynamic without using -static.
- if(iself && strncmp(p, "-static", 7) == 0 && (p[7]==' ' || p[7]=='\x00')) {
- for(i=0; i<argc; i++) {
- if(strcmp(argv[i], "-rdynamic") == 0)
- argv[i] = "-static";
- }
- }
-
- p = strchr(p + 1, ' ');
- }
-
- argv[argc] = nil;
-
- quotefmtinstall();
- if(debug['v']) {
- Bprint(&bso, "host link:");
- for(i=0; i<argc; i++)
- Bprint(&bso, " %q", argv[i]);
- Bprint(&bso, "\n");
- Bflush(&bso);
- }
-
- if(runcmd(argv) < 0) {
- ctxt->cursym = 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, "<nil>");
- 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, "<nil>");
- } 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; i<s->nr; 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; i<s->nr; 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; i<s->nr; 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; i<s->nr; 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;
-}
+++ /dev/null
-// 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
-
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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; i<nload; i++)
- loadsize += 4*(load[i].ndata+2);
- if(macho64) {
- loadsize += 18*4*nseg;
- loadsize += 20*4*nsect;
- } else {
- loadsize += 14*4*nseg;
- loadsize += 17*4*nsect;
- }
-
- if(macho64)
- thearch.lput(0xfeedfacf);
- else
- thearch.lput(0xfeedface);
- thearch.lput(machohdr.cpu);
- thearch.lput(machohdr.subcpu);
- if(linkmode == LinkExternal)
- thearch.lput(1); /* file type - mach object */
- else
- thearch.lput(2); /* file type - mach executable */
- thearch.lput(nload+nseg+ndebug);
- thearch.lput(loadsize);
- thearch.lput(1); /* flags - no undefines */
- if(macho64)
- thearch.lput(0); /* reserved */
-
- for(i=0; i<nseg; i++) {
- s = &seg[i];
- if(macho64) {
- thearch.lput(25); /* segment 64 */
- thearch.lput(72+80*s->nsect);
- 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; j<s->nsect; 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; i<nload; i++) {
- l = &load[i];
- thearch.lput(l->type);
- thearch.lput(4*(l->ndata+2));
- for(j=0; j<l->ndata; 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<<msect->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; i<ndylib; i++) {
- ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */
- ml->data[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; i<ndynexp; i++)
- dynexp[i]->reachable = 1;
- machogenasmsym(addsym);
- sortsym = mal(nsortsym * sizeof sortsym[0]);
- nsortsym = 0;
- machogenasmsym(addsym);
- qsort(sortsym, nsortsym, sizeof sortsym[0], machoscmp);
- for(i=0; i<nsortsym; i++)
- sortsym[i]->dynid = 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; i<nsortsym; i++) {
- s = sortsym[i];
- adduint32(ctxt, symtab, symstr->size);
-
- // 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; ri<sym->nr; 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);
-}
+++ /dev/null
-// 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*);
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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; i<nfiles; i++) {
- f = files[i];
- if(f->type != 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; i<pcln->npcdata; 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; i<pcln->nfuncdata; 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);
-}
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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; i<nexport; i++)
- size += strlen(dexport[i]->extname) + 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; i<sizeof(e); i++)
- cput(((char*)&e)[i]);
- // put EXPORT Address Table
- for(i=0; i<nexport; i++)
- lputl(dexport[i]->value - PEBASE);
- // put EXPORT Name Pointer Table
- v = e.Name + strlen(outfile)+1;
- for(i=0; i<nexport; i++) {
- lputl(v);
- v += strlen(dexport[i]->extname)+1;
- }
- // put EXPORT Ordinal Table
- for(i=0; i<nexport; i++)
- wputl(i);
- // put Names
- strnput(outfile, strlen(outfile)+1);
- for(i=0; i<nexport; i++)
- strnput(dexport[i]->extname, 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.
- * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
- */
-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; i<ncoffsym; i++) {
- s = &coffsym[i];
- if(s->strtbloff == 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; i<strtblnextoff; i++)
- cput(strtbl[i]);
- strnput("", h->SizeOfRawData - 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; ri<rsrcsym->nr; 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();
-}
+++ /dev/null
-// 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);
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "lib.h"
-#include "elf.h"
-#include "macho.h"
-#include "dwarf.h"
-#include "pe.h"
-#include <ar.h>
-
-char *noname = "<none>";
-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; i<argc; i++)
- if(strcmp(argv[i], "-crash_for_testing") == 0)
- *(volatile int*)0 = 0;
-
- if(thearch.thechar == '5' && ctxt->goarm == 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();
-}
+++ /dev/null
-// 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#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);
- }
- }
-}
#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,
-};
-*/