diff options
Diffstat (limited to 'src/cmd/ld/elf.c')
-rw-r--r-- | src/cmd/ld/elf.c | 558 |
1 files changed, 0 insertions, 558 deletions
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c deleted file mode 100644 index fc917b203..000000000 --- a/src/cmd/ld/elf.c +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "l.h" -#include "lib.h" -#include "../ld/elf.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. - */ -#define NSECT 32 - -int iself; - -static int elf64; -static ElfEhdr hdr; -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; - -/* - 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(thechar) { - // 64-bit architectures - case '6': - elf64 = 1; - hdr.phoff = ELF64HDRSIZE; /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */ - hdr.shoff = ELF64HDRSIZE; /* Will move as we add PHeaders */ - hdr.ehsize = ELF64HDRSIZE; /* Must be ELF64HDRSIZE */ - hdr.phentsize = ELF64PHDRSIZE; /* Must be ELF64PHDRSIZE */ - hdr.shentsize = ELF64SHDRSIZE; /* Must be ELF64SHDRSIZE */ - break; - - // 32-bit architectures - default: - hdr.phoff = ELF32HDRSIZE; /* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */ - hdr.shoff = ELF32HDRSIZE; /* Will move as we add PHeaders */ - hdr.ehsize = ELF32HDRSIZE; /* Must be ELF32HDRSIZE */ - hdr.phentsize = ELF32PHDRSIZE; /* Must be ELF32PHDRSIZE */ - hdr.shentsize = ELF32SHDRSIZE; /* Must be ELF32SHDRSIZE */ - } -} - -void -elf64phdr(ElfPhdr *e) -{ - LPUT(e->type); - LPUT(e->flags); - VPUT(e->off); - VPUT(e->vaddr); - VPUT(e->paddr); - VPUT(e->filesz); - VPUT(e->memsz); - VPUT(e->align); -} - -void -elf32phdr(ElfPhdr *e) -{ - LPUT(e->type); - LPUT(e->off); - LPUT(e->vaddr); - LPUT(e->paddr); - LPUT(e->filesz); - LPUT(e->memsz); - LPUT(e->flags); - LPUT(e->align); -} - -void -elf64shdr(ElfShdr *e) -{ - LPUT(e->name); - LPUT(e->type); - VPUT(e->flags); - VPUT(e->addr); - VPUT(e->off); - VPUT(e->size); - LPUT(e->link); - LPUT(e->info); - VPUT(e->addralign); - VPUT(e->entsize); -} - -void -elf32shdr(ElfShdr *e) -{ - LPUT(e->name); - LPUT(e->type); - LPUT(e->flags); - LPUT(e->addr); - LPUT(e->off); - LPUT(e->size); - LPUT(e->link); - LPUT(e->info); - LPUT(e->addralign); - LPUT(e->entsize); -} - -uint32 -elfwriteshdrs(void) -{ - int i; - - if (elf64) { - for (i = 0; i < hdr.shnum; i++) - elf64shdr(shdr[i]); - return hdr.shnum * ELF64SHDRSIZE; - } - for (i = 0; i < hdr.shnum; i++) - elf32shdr(shdr[i]); - return hdr.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 < hdr.phnum; i++) - elf64phdr(phdr[i]); - return hdr.phnum * ELF64PHDRSIZE; - } - for (i = 0; i < hdr.phnum; i++) - elf32phdr(phdr[i]); - return hdr.phnum * ELF32PHDRSIZE; -} - -ElfPhdr* -newElfPhdr(void) -{ - ElfPhdr *e; - - e = mal(sizeof *e); - if (hdr.phnum >= NSECT) - diag("too many phdrs"); - else - phdr[hdr.phnum++] = e; - if (elf64) - hdr.shoff += ELF64PHDRSIZE; - else - hdr.shoff += ELF32PHDRSIZE; - return e; -} - -ElfShdr* -newElfShstrtab(vlong name) -{ - hdr.shstrndx = hdr.shnum; - return newElfShdr(name); -} - -ElfShdr* -newElfShdr(vlong name) -{ - ElfShdr *e; - - e = mal(sizeof *e); - e->name = name; - if (hdr.shnum >= NSECT) { - diag("too many shdrs"); - } else { - shdr[hdr.shnum++] = e; - } - return e; -} - -ElfEhdr* -getElfEhdr(void) -{ - return &hdr; -} - -uint32 -elf64writehdr(void) -{ - int i; - - for (i = 0; i < EI_NIDENT; i++) - cput(hdr.ident[i]); - WPUT(hdr.type); - WPUT(hdr.machine); - LPUT(hdr.version); - VPUT(hdr.entry); - VPUT(hdr.phoff); - VPUT(hdr.shoff); - LPUT(hdr.flags); - WPUT(hdr.ehsize); - WPUT(hdr.phentsize); - WPUT(hdr.phnum); - WPUT(hdr.shentsize); - WPUT(hdr.shnum); - WPUT(hdr.shstrndx); - return ELF64HDRSIZE; -} - -uint32 -elf32writehdr(void) -{ - int i; - - for (i = 0; i < EI_NIDENT; i++) - cput(hdr.ident[i]); - WPUT(hdr.type); - WPUT(hdr.machine); - LPUT(hdr.version); - LPUT(hdr.entry); - LPUT(hdr.phoff); - LPUT(hdr.shoff); - LPUT(hdr.flags); - WPUT(hdr.ehsize); - WPUT(hdr.phentsize); - WPUT(hdr.phnum); - WPUT(hdr.shentsize); - WPUT(hdr.shnum); - WPUT(hdr.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(Sym *s, int tag, uint64 val) -{ - if(elf64) { - adduint64(s, tag); - adduint64(s, val); - } else { - adduint32(s, tag); - adduint32(s, val); - } -} - -void -elfwritedynentsym(Sym *s, int tag, Sym *t) -{ - if(elf64) - adduint64(s, tag); - else - adduint32(s, tag); - addaddr(s, t); -} - -void -elfwritedynentsymsize(Sym *s, int tag, Sym *t) -{ - if(elf64) - adduint64(s, tag); - else - adduint32(s, tag); - addsize(s, t); -} - -int -elfwriteinterp(void) -{ - int n; - - if(interp == nil) - return 0; - - n = strlen(interp)+1; - seek(cout, ELFRESERVE-n, 0); - ewrite(cout, interp, n); - return n; -} - -void -elfinterp(ElfShdr *sh, uint64 startva, char *p) -{ - int n; - - interp = p; - n = strlen(interp)+1; - sh->addr = startva + ELFRESERVE - n; - sh->off = ELFRESERVE - n; - sh->size = n; -} - -extern int nelfsym; -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) -{ - Sym *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 = lookup(".hash", 0); - s->type = SELFDATA; - 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) { - 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=allsym; sy!=S; sy=sy->allsym) { - if (sy->dynid <= 0) - continue; - - if(sy->dynimpvers) - need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers); - - name = sy->dynimpname; - if(name == nil) - name = sy->name; - hc = elfhash((uchar*)name); - - b = hc % nbucket; - chain[sy->dynid] = buckets[b]; - buckets[b] = sy->dynid; - } - - adduint32(s, nbucket); - adduint32(s, nsym); - for(i = 0; i<nbucket; i++) - adduint32(s, buckets[i]); - for(i = 0; i<nsym; i++) - adduint32(s, chain[i]); - - free(chain); - free(buckets); - - // version symbols - dynstr = lookup(".dynstr", 0); - s = lookup(".gnu.version_r", 0); - i = 2; - nfile = 0; - for(l=needlib; l; l=l->next) { - nfile++; - // header - adduint16(s, 1); // table version - j = 0; - for(x=l->aux; x; x=x->next) - j++; - adduint16(s, j); // aux count - adduint32(s, addstring(dynstr, l->file)); // file string offset - adduint32(s, 16); // offset from header to first aux - if(l->next) - adduint32(s, 16+j*16); // offset from this header to next - else - adduint32(s, 0); - - for(x=l->aux; x; x=x->next) { - x->num = i++; - // aux struct - adduint32(s, elfhash((uchar*)x->vers)); // hash - adduint16(s, 0); // flags - adduint16(s, x->num); // other - index we refer to this by - adduint32(s, addstring(dynstr, x->vers)); // version string offset - if(x->next) - adduint32(s, 16); // offset from this aux to next - else - adduint32(s, 0); - } - } - - // version references - s = lookup(".gnu.version", 0); - for(i=0; i<nsym; i++) { - if(i == 0) - adduint16(s, 0); // first entry - no symbol - else if(need[i] == nil) - adduint16(s, 1); // global - else - adduint16(s, need[i]->num); - } - - free(need); - - s = lookup(".dynamic", 0); - elfverneed = nfile; - if(elfverneed) { - elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0)); - elfwritedynent(s, DT_VERNEEDNUM, nfile); - elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0)); - } - 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->len; - ph->off = seg->fileoff; - ph->filesz = seg->filelen; - ph->align = INITRND; - - return ph; -} - -ElfShdr* -elfshbits(Section *sect) -{ - int i, off; - ElfShdr *sh; - - for(i=0; i<nelfstr; i++) { - if(strcmp(sect->name, elfstr[i].s) == 0) { - off = elfstr[i].off; - goto found; - } - } - diag("cannot find elf name %s", sect->name); - errorexit(); - return nil; - -found: - sh = newElfShdr(off); - 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; - sh->addr = sect->vaddr; - sh->addralign = PtrSize; - sh->size = sect->len; - sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr; - - return sh; -} |