| // 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; |
| |
| /* |
| 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; |
| } |
| |
| 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 = malloc(sizeof *e); |
| memset(e, 0, 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 = malloc(sizeof *e); |
| memset(e, 0, 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); |
| write(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; |
| } |