From 1593b1fc23f039b519d71e092cadaa90b42a266a Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 17 Jul 2009 14:32:37 -0700 Subject: [PATCH] First steps towards cleaner support for ELF64 in 6l. R=rsc DELTA=337 (165 added, 119 deleted, 53 changed) OCL=31786 CL=31794 --- src/cmd/6l/Makefile | 4 + src/cmd/6l/asm.c | 217 +++++++++++--------------------------------- src/cmd/6l/elf64.c | 6 ++ src/cmd/6l/l.h | 10 +- src/cmd/6l/obj.c | 3 +- src/cmd/ld/elf64.c | 108 ++++++++++++++++++++++ src/cmd/ld/elf64.h | 89 ++++++++++++++++++ 7 files changed, 265 insertions(+), 172 deletions(-) create mode 100644 src/cmd/6l/elf64.c create mode 100644 src/cmd/ld/elf64.c create mode 100644 src/cmd/ld/elf64.h diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile index eba976c638..bcbdb3de7d 100644 --- a/src/cmd/6l/Makefile +++ b/src/cmd/6l/Makefile @@ -10,6 +10,7 @@ TARG=\ OFILES=\ asm.$O\ compat.$O\ + elf64.$O\ enam.$O\ go.$O\ list.$O\ @@ -21,6 +22,7 @@ OFILES=\ HFILES=\ l.h\ ../6l/6.out.h\ + ../ld/elf64.h\ $(TARG): $(OFILES) @@ -38,3 +40,5 @@ install: $(TARG) cp $(TARG) $(BIN)/$(TARG) go.o: ../ld/go.c + +elf64.o: ../ld/elf64.c diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index b981570c0d..fcfbc6ad2d 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -29,6 +29,7 @@ // THE SOFTWARE. #include "l.h" +#include "../ld/elf64.h" #define Dbufslop 100 @@ -126,6 +127,7 @@ asmb(void) vlong vl, va, fo, w, symo; int strtabsize; vlong symdatva = 0x99LL<<32; + Elf64SHdr *sh; strtabsize = 0; @@ -194,7 +196,7 @@ asmb(void) case 7: debug['8'] = 1; /* 64-bit addresses */ seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0); - strtabsize = linuxstrtable(); + strtabsize = elf64strtable(); cflush(); v = rnd(HEADR+textsize, INITRND); seek(cout, v, 0); @@ -448,7 +450,7 @@ asmb(void) va = INITTEXT & ~((vlong)INITRND - 1); w = HEADR+textsize; - linuxphdr(1, /* text - type = PT_LOAD */ + elf64phdr(1, /* text - type = PT_LOAD */ 1L+4L, /* text - flags = PF_X+PF_R */ 0, /* file offset */ va, /* vaddr */ @@ -461,7 +463,7 @@ asmb(void) va = rnd(va+w, INITRND); w = datsize; - linuxphdr(1, /* data - type = PT_LOAD */ + elf64phdr(1, /* data - type = PT_LOAD */ 2L+4L, /* data - flags = PF_W+PF_R */ fo, /* file offset */ va, /* vaddr */ @@ -471,7 +473,7 @@ asmb(void) INITRND); /* alignment */ if(!debug['s']) { - linuxphdr(1, /* data - type = PT_LOAD */ + elf64phdr(1, /* data - type = PT_LOAD */ 2L+4L, /* data - flags = PF_W+PF_R */ symo, /* file offset */ symdatva, /* vaddr */ @@ -481,7 +483,7 @@ asmb(void) INITRND); /* alignment */ } - linuxphdr(0x6474e551, /* gok - type = gok */ + elf64phdr(0x6474e551, /* gok - type = gok */ 1L+2L+4L, /* gok - flags = PF_X+PF_W+PF_R */ 0, /* file offset */ 0, /* vaddr */ @@ -490,75 +492,57 @@ asmb(void) 0, /* memory size */ 8); /* alignment */ - linuxshdr(nil, /* name */ - 0, /* type */ - 0, /* flags */ - 0, /* addr */ - 0, /* off */ - 0, /* size */ - 0, /* link */ - 0, /* info */ - 0, /* align */ - 0); /* entsize */ + sh = newElf64SHdr(); + elf64shdr(nil, sh); stroffset = 1; /* 0 means no name, so start at 1 */ fo = HEADR; va = (INITTEXT & ~((vlong)INITRND - 1)) + HEADR; w = textsize; - linuxshdr(".text", /* name */ - 1, /* type */ - 6, /* flags */ - va, /* addr */ - fo, /* off */ - w, /* size */ - 0, /* link */ - 0, /* info */ - 8, /* align */ - 0); /* entsize */ + sh = newElf64SHdr(); + sh->type = 1; + sh->flags = 6; + sh->addr = va; + sh->off = fo; + sh->size = w; + sh->addralign = 8; + elf64shdr(".text", sh); fo = rnd(fo+w, INITRND); va = rnd(va+w, INITRND); w = datsize; - linuxshdr(".data", /* name */ - 1, /* type */ - 3, /* flags */ - va, /* addr */ - fo, /* off */ - w, /* size */ - 0, /* link */ - 0, /* info */ - 8, /* align */ - 0); /* entsize */ + sh = newElf64SHdr(); + sh->type = 1; + sh->flags = 3; + sh->addr = va; + sh->off = fo; + sh->size = w; + sh->addralign = 8; + elf64shdr(".data", sh); fo += w; va += w; w = bsssize; - linuxshdr(".bss", /* name */ - 8, /* type */ - 3, /* flags */ - va, /* addr */ - fo, /* off */ - w, /* size */ - 0, /* link */ - 0, /* info */ - 8, /* align */ - 0); /* entsize */ + sh = newElf64SHdr(); + sh->type = 8; + sh->flags = 3; + sh->addr = va; + sh->off = fo; + sh->size = w; + sh->addralign = 8; + elf64shdr(".bss", sh); w = strtabsize; - linuxshdr(".shstrtab", /* name */ - 3, /* type */ - 0, /* flags */ - 0, /* addr */ - fo, /* off */ - w, /* size */ - 0, /* link */ - 0, /* info */ - 1, /* align */ - 0); /* entsize */ + sh = newElf64SHdr(); + sh->type = 3; + sh->off = fo; + sh->size = w; + sh->addralign = 1; + elf64shdr(".shstrtab", sh); if (debug['s']) break; @@ -566,30 +550,25 @@ asmb(void) fo = symo+8; w = symsize; - linuxshdr(".gosymtab", /* name */ - 1, /* type 1 = SHT_PROGBITS */ - 0, /* flags */ - 0, /* addr */ - fo, /* off */ - w, /* size */ - 0, /* link */ - 0, /* info */ - 1, /* align */ - 24); /* entsize */ + sh = newElf64SHdr(); + sh->type = 1; /* type 1 = SHT_PROGBITS */ + sh->off = fo; + sh->size = w; + sh->addralign = 1; + sh->entsize = 24; + elf64shdr(".gosymtab", sh); fo += w; w = lcsize; - linuxshdr(".gopclntab", /* name */ - 1, /* type 1 = SHT_PROGBITS*/ - 0, /* flags */ - 0, /* addr */ - fo, /* off */ - w, /* size */ - 0, /* link */ - 0, /* info */ - 1, /* align */ - 24); /* entsize */ + sh = newElf64SHdr(); + sh->type = 1; /* type 1 = SHT_PROGBITS */ + sh->off = fo; + sh->size = w; + sh->addralign = 1; + sh->entsize = 24; + elf64shdr(".gopclntab", sh); + break; } cflush(); @@ -899,91 +878,3 @@ machheadr(void) return a*4; } - -uint32 -linuxheadr(void) -{ - uint32 a; - - a = 64; /* a.out header */ - - a += 56; /* page zero seg */ - a += 56; /* text seg */ - a += 56; /* stack seg */ - - a += 64; /* nil sect */ - a += 64; /* .text sect */ - a += 64; /* .data seg */ - a += 64; /* .bss sect */ - a += 64; /* .shstrtab sect - strings for headers */ - if (!debug['s']) { - a += 56; /* symdat seg */ - a += 64; /* .gosymtab sect */ - a += 64; /* .gopclntab sect */ - } - - return a; -} - - -void -linuxphdr(int type, int flags, vlong foff, - vlong vaddr, vlong paddr, - vlong filesize, vlong memsize, vlong align) -{ - - lputl(type); /* text - type = PT_LOAD */ - lputl(flags); /* text - flags = PF_X+PF_R */ - vputl(foff); /* file offset */ - vputl(vaddr); /* vaddr */ - vputl(paddr); /* paddr */ - vputl(filesize); /* file size */ - vputl(memsize); /* memory size */ - vputl(align); /* alignment */ -} - -void -linuxshdr(char *name, uint32 type, vlong flags, vlong addr, vlong off, - vlong size, uint32 link, uint32 info, vlong align, vlong entsize) -{ - lputl(stroffset); - lputl(type); - vputl(flags); - vputl(addr); - vputl(off); - vputl(size); - lputl(link); - lputl(info); - vputl(align); - vputl(entsize); - - if(name != nil) - stroffset += strlen(name)+1; -} - -int -putstrtab(char* name) { - int w; - - w = strlen(name)+1; - strnput(name, w); - return w; -} - -int -linuxstrtable(void) -{ - int size; - - size = 0; - size += putstrtab(""); - size += putstrtab(".text"); - size += putstrtab(".data"); - size += putstrtab(".bss"); - size += putstrtab(".shstrtab"); - if (!debug['s']) { - size += putstrtab(".gosymtab"); - size += putstrtab(".gopclntab"); - } - return size; -} diff --git a/src/cmd/6l/elf64.c b/src/cmd/6l/elf64.c new file mode 100644 index 0000000000..20e502fb9a --- /dev/null +++ b/src/cmd/6l/elf64.c @@ -0,0 +1,6 @@ +// 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 "../ld/elf64.c" diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index 41e233f62a..e09579a6e7 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -432,9 +432,11 @@ int relinv(int); int32 reuse(Prog*, Sym*); vlong rnd(vlong, vlong); void span(void); +void strnput(char*, int); void undef(void); void undefsym(Sym*); vlong vaddr(Adr*); +void vputl(vlong); void wput(ushort); void xdefine(char*, int, vlong); void xfol(Prog*); @@ -448,14 +450,6 @@ void machstack(vlong); void machdylink(void); uint32 machheadr(void); -uint32 linuxheadr(void); -void linuxphdr(int type, int flags, vlong foff, - vlong vaddr, vlong paddr, - vlong filesize, vlong memsize, vlong align); -void linuxshdr(char *name, uint32 type, vlong flags, vlong addr, vlong off, - vlong size, uint32 link, uint32 info, vlong align, vlong entsize); -int linuxstrtable(void); - #pragma varargck type "D" Adr* #pragma varargck type "P" Prog* diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index bcaa9da3b1..a2a520396f 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -30,6 +30,7 @@ #define EXTERN #include "l.h" +#include "../ld/elf64.h" #include char *noname = ""; @@ -196,7 +197,7 @@ main(int argc, char *argv[]) INITRND = 4096; break; case 7: /* elf64 executable */ - HEADR = linuxheadr(); + HEADR = elf64headr(); if(INITTEXT == -1) INITTEXT = (1<<22)+HEADR; if(INITDAT == -1) diff --git a/src/cmd/ld/elf64.c b/src/cmd/ld/elf64.c new file mode 100644 index 0000000000..483b51ca33 --- /dev/null +++ b/src/cmd/ld/elf64.c @@ -0,0 +1,108 @@ +// 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. + +// Support for 64-bit Elf binaries + +#include "../ld/elf64.h" + +void +elf64phdr(int type, int flags, vlong foff, + vlong vaddr, vlong paddr, + vlong filesize, vlong memsize, vlong align) +{ + + lputl(type); /* type */ + lputl(flags); /* flags */ + vputl(foff); /* file offset */ + vputl(vaddr); /* vaddr */ + vputl(paddr); /* paddr */ + vputl(filesize); /* file size */ + vputl(memsize); /* memory size */ + vputl(align); /* alignment */ +} + +void +elf64shdr(char *name, Elf64SHdr *e) +{ + lputl(e->name); + lputl(e->type); + vputl(e->flags); + vputl(e->addr); + vputl(e->off); + vputl(e->size); + lputl(e->link); + lputl(e->info); + vputl(e->addralign); + vputl(e->entsize); + + if(name != nil) + stroffset += strlen(name)+1; +} + +int +putelf64strtab(char* name) +{ + int w; + + w = strlen(name)+1; + strnput(name, w); + return w; +} + + +int +elf64strtable(void) +{ + int size; + + size = 0; + size += putelf64strtab(""); + size += putelf64strtab(".text"); + size += putelf64strtab(".data"); + size += putelf64strtab(".bss"); + size += putelf64strtab(".shstrtab"); + if (!debug['s']) { + size += putelf64strtab(".gosymtab"); + size += putelf64strtab(".gopclntab"); + } + return size; +} + + +uint32 +elf64headr(void) +{ + uint32 a; + + a = 64; /* a.out header */ + + a += 56; /* page zero seg */ + a += 56; /* text seg */ + a += 56; /* stack seg */ + + a += 64; /* nil sect */ + a += 64; /* .text sect */ + a += 64; /* .data seg */ + a += 64; /* .bss sect */ + a += 64; /* .shstrtab sect - strings for headers */ + if (!debug['s']) { + a += 56; /* symdat seg */ + a += 64; /* .gosymtab sect */ + a += 64; /* .gopclntab sect */ + } + + return a; +} + +Elf64SHdr* +newElf64SHdr() +{ + Elf64SHdr *e; + + e = malloc(sizeof *e); + memset(e, 0, sizeof *e); + e->name = stroffset; + return e; +} + diff --git a/src/cmd/ld/elf64.h b/src/cmd/ld/elf64.h new file mode 100644 index 0000000000..cd4964ba3e --- /dev/null +++ b/src/cmd/ld/elf64.h @@ -0,0 +1,89 @@ +/* + * 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. + * + */ + +typedef uint64 Elf64_Addr; /* Unsigned program address */ +typedef uint64 Elf64_Off; /* Unsigned file offset */ +typedef uint16 Elf64_Half; /* Unsigned medium integer */ +typedef uint32 Elf64_Word; /* Unsigned integer */ +typedef int32 Elf64_Sword; /* Signed integer */ +typedef uint64 Elf64_Xword; /* Unsigned long integer */ +typedef int64 Elf64_Sxword; /* Signed long integer */ + +typedef struct Elf64Hdr Elf64Hdr; +typedef struct Elf64SHdr Elf64SHdr; + +struct Elf64Hdr +{ + uchar ident[16]; /* ELF identification */ + Elf64_Half type; /* Object file type */ + Elf64_Half machine; /* Machine type */ + Elf64_Word version; /* Object file version */ + Elf64_Addr entry; /* Entry point address */ + Elf64_Off phoff; /* Program header offset */ + Elf64_Off shoff; /* Section header offset */ + Elf64_Word flags; /* Processor-specific flags */ + Elf64_Half ehsize; /* ELF header size */ + Elf64_Half phentsize; /* Size of program header entry */ + Elf64_Half phnum; /* Number of program header entries */ + Elf64_Half shentsize; /* Size of section header entry */ + Elf64_Half shnum; /* Number of section header entries */ + Elf64_Half shstrndx; /* Section name string table index */ +}; + +struct Elf64SHdr +{ + Elf64_Word name; /* Section name */ + Elf64_Word type; /* Section type */ + Elf64_Xword flags; /* Section attributes */ + Elf64_Addr addr; /* Virtual address in memory */ + Elf64_Off off; /* Offset in file */ + Elf64_Xword size; /* Size of section */ + Elf64_Word link; /* Link to other section */ + Elf64_Word info; /* Miscellaneous information */ + Elf64_Xword addralign; /* Address alignment boundary */ + Elf64_Xword entsize; /* Size of entries, if section has table */ +}; + +Elf64SHdr *newElf64SHdr(); +uint32 elf64headr(void); +void elf64phdr(int type, int flags, vlong foff, + vlong vaddr, vlong paddr, + vlong filesize, vlong memsize, vlong align); +void elf64shdr(char*, Elf64SHdr*); +int elf64strtable(void);