From: Rob Pike Date: Tue, 21 Jul 2009 22:10:47 +0000 (-0700) Subject: make 6l produce dynamically linked binaries (although they are fully statically linke... X-Git-Tag: weekly.2009-11-06~1081 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=3d42e691b931d34f2a3fee0885368f42d84665fb;p=gostls13.git make 6l produce dynamically linked binaries (although they are fully statically linked as far as go is concerned). the -d flag is now flipped; as on the mac, -d disables dynamic. much remains to be improved to move the output closer to the gcc format. R=rsc DELTA=366 (310 added, 30 deleted, 26 changed) OCL=31929 CL=31951 --- diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index c1d0a4d97a..850077b80c 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -35,6 +35,10 @@ #define PADDR(a) ((uint32)(a) & ~0x80000000) +char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2"; + +char zeroes[32]; + vlong entryvalue(void) { @@ -124,11 +128,11 @@ asmb(void) int32 v, magic; int a, nl; uchar *op1; - vlong vl, va, fo, w, symo; + vlong vl, va, startva, fo, w, symo, hashoff; vlong symdatva = 0x99LL<<32; Elf64Hdr *eh; - Elf64PHdr *ph; - Elf64SHdr *sh; + Elf64PHdr *ph, *pph; + Elf64SHdr *sh, *dynsh; if(debug['v']) Bprint(&bso, "%5.2f asmb\n", cputime()); @@ -237,7 +241,7 @@ asmb(void) symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND); break; case 7: - symo = rnd(HEADR+textsize, INITRND)+datsize+STRTABSIZE; + symo = rnd(HEADR+textsize, INITRND)+datsize; symo = rnd(symo, INITRND); break; } @@ -419,16 +423,132 @@ asmb(void) /* elf amd-64 */ fo = 0; - va = INITTEXT & ~((vlong)INITRND - 1); + startva = INITTEXT - HEADR; + va = startva; w = HEADR+textsize; + /* This null SHdr must appear before all others */ + sh = newElf64SHdr(""); + + pph = nil; /* silence compiler */ + + /* Dynamic linking sections */ + if (!debug['d']) { /* -d suppresses dynamic loader format */ + + /* P headers */ + /* program header info */ + pph = newElf64PHdr(); + pph->type = PT_PHDR; + pph->flags = PF_R + PF_X; + pph->off = ELF64HDRSIZE; + pph->vaddr = startva + pph->off; + pph->paddr = startva + pph->off; + pph->align = 8; + + /* interpreter */ + ph = newElf64PHdr(); + ph->type = PT_INTERP; + ph->flags = PF_R; + ph->off = startelf(); + ph->vaddr = startva; + ph->paddr = startva; + write(cout, linuxdynld, sizeof linuxdynld); + ph->filesz = endelf() - ph->off; + ph->align = 1; + + /* dynamic load section */ + ph = newElf64PHdr(); + ph->type = PT_LOAD; + ph->flags = PF_R + PF_W; + ph->off = 0; + ph->vaddr = startva + ph->off; + ph->paddr = startva + ph->off; + ph->align = 8; + + /* S headers inside dynamic load section */ + dynsh = newElf64SHdr(".dynamic"); // must be first + dynsh->off = startelf(); + + seek(cout, ELFDYNAMICSIZE, 1); // leave room for dynamic table + + sh = newElf64SHdr(".hash"); + sh->type = SHT_HASH; + sh->flags = SHF_ALLOC; + sh->entsize = 4; + sh->addr = va; + sh->off = seek(cout, 0, 1); + hashoff = sh->off; + sh->addr = startva + sh->off; + /* temporary hack: 8 zeroes means 0 buckets, 0 chains */ + write(cout, zeroes, 8); + sh->size = endelf() - sh->off; + sh->addralign = 8; + + sh = newElf64SHdr(".got"); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_WRITE; + sh->entsize = 8; + sh->addr = va; + sh->off = startelf(); + sh->addr = startva + sh->off; + sh->size = endelf() - sh->off; + sh->addralign = 8; + + sh = newElf64SHdr(".got.plt"); + sh->type = SHT_PROGBITS; + sh->flags = SHF_ALLOC+SHF_WRITE; + sh->entsize = 8; + sh->addr = va; + sh->off = startelf(); + sh->addr = startva + sh->off; + sh->size = endelf() - sh->off; + sh->addralign = 8; + + /* +8 necessary for now to silence readelf addressing at end of hash section */ + ph->filesz = endelf() - ph->off +8; /* dynamic section maps these shdrs' data */ + ph->memsz = ph->filesz; + + dynsh->type = SHT_DYNAMIC; + dynsh->flags = SHF_ALLOC+SHF_WRITE; + dynsh->entsize = 16; + dynsh->addr = startva + dynsh->off; + seek(cout, dynsh->off, 0); + elf64writedynent(DT_HASH, startva+hashoff); + elf64writedynent(DT_STRTAB, startva+ELF64FULLHDRSIZE-STRTABSIZE); + elf64writedynent(DT_SYMTAB, startva); + elf64writedynent(DT_RELA, startva); + elf64writedynent(DT_RELASZ, 0); // size of the whole rela in bytes + elf64writedynent(DT_RELAENT, ELF64RELASIZE); + elf64writedynent(DT_STRSZ, STRTABSIZE); + elf64writedynent(DT_SYMENT, 0); + elf64writedynent(DT_REL, startva); + elf64writedynent(DT_RELSZ, 0); + elf64writedynent(DT_RELENT, ELF64RELSIZE); + elf64writedynent(DT_NULL, 0); + cflush(); + dynsh->size = seek(cout, 0, 1) - dynsh->off; + dynsh->addralign = 8; + + /* dynamic section */ + ph = newElf64PHdr(); + ph->type = PT_DYNAMIC; + ph->flags = PF_R + PF_W; + ph->off = dynsh->off; + ph->filesz = dynsh->size; + ph->memsz = dynsh->size; + ph->vaddr = startva + ph->off; + ph->paddr = startva + ph->off; + ph->align = 8; + } + ph = newElf64PHdr(); - ph->type = PT_LOAD; + ph->type = PT_LOAD; ph->flags = PF_X+PF_R; - ph->vaddr = va; - ph->paddr = va; - ph->filesz = w; - ph->memsz = w; + ph->vaddr = va + ELF64RESERVE; + ph->paddr = va + ELF64RESERVE; + ph->off = ELF64RESERVE; + ph->filesz = w - ELF64RESERVE; + ph->memsz = w - ELF64RESERVE; ph->align = INITRND; fo = rnd(fo+w, INITRND); @@ -462,11 +582,8 @@ asmb(void) ph->flags = PF_X+PF_W+PF_R; ph->align = 8; - sh = newElf64SHdr(""); - - stroffset = 1; /* 0 means no name, so start at 1 */ - fo = HEADR; - va = (INITTEXT & ~((vlong)INITRND - 1)) + HEADR; + fo = ELF64RESERVE; + va = startva + fo; w = textsize; sh = newElf64SHdr(".text"); @@ -501,38 +618,37 @@ asmb(void) sh->size = w; sh->addralign = 8; - w = STRTABSIZE; + if (!debug['s']) { + fo = symo+8; + w = symsize; + + sh = newElf64SHdr(".gosymtab"); + sh->type = SHT_PROGBITS; + sh->off = fo; + sh->size = w; + sh->addralign = 1; + sh->entsize = 24; + + fo += w; + w = lcsize; + + sh = newElf64SHdr(".gopclntab"); + sh->type = SHT_PROGBITS; + sh->off = fo; + sh->size = w; + sh->addralign = 1; + sh->entsize = 24; + } sh = newElf64SHdr(".shstrtab"); sh->type = SHT_STRTAB; - sh->off = fo; - sh->size = w; - sh->addralign = 1; - - if (debug['s']) - break; - - fo = symo+8; - w = symsize; - - sh = newElf64SHdr(".gosymtab"); - sh->type = SHT_PROGBITS; - sh->off = fo; - sh->size = w; + sh->off = startelf(); + sh->addr = sh->off + startva; sh->addralign = 1; - sh->entsize = 24; - - fo += w; - w = lcsize; - - sh = newElf64SHdr(".gopclntab"); - sh->type = SHT_PROGBITS; - sh->off = fo; - sh->size = w; - sh->addralign = 1; - sh->entsize = 24; + elf64writestrtable(); + sh->size = endelf() - sh->off; - // main header */ + /* Main header */ eh = getElf64Hdr(); eh->ident[EI_MAG0] = '\177'; eh->ident[EI_MAG1] = 'E'; @@ -547,6 +663,12 @@ asmb(void) eh->version = EV_CURRENT; eh->entry = entryvalue(); + if (!debug['d']) { + pph->filesz = eh->phnum * ELF64PHDRSIZE; + pph->memsz = pph->filesz; + } + + seek(cout, 0, 0); a = 0; a += elf64writehdr(); a += elf64writephdrs(); @@ -556,11 +678,6 @@ asmb(void) } cflush(); - /* string table */ - seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0); - elf64writestrtable(); - cflush(); - break; } cflush(); diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index 4a7cfc8347..ea6f2c9b5c 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -353,7 +353,6 @@ EXTERN int imports, nimports; EXTERN int exports, nexports; EXTERN char* EXPTAB; EXTERN Prog undefp; -EXTERN uint32 stroffset; EXTERN vlong textstksiz; EXTERN vlong textarg; diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index 8538e064e4..66d1e7eede 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -197,7 +197,7 @@ main(int argc, char *argv[]) INITRND = 4096; break; case 7: /* elf64 executable */ - HEADR = ELF64FULLHDRSIZE; + HEADR = ELF64RESERVE; if(INITTEXT == -1) INITTEXT = (1<<22)+HEADR; if(INITDAT == -1) diff --git a/src/cmd/ld/elf64.c b/src/cmd/ld/elf64.c index ea1a39b418..dc9f4196b1 100644 --- a/src/cmd/ld/elf64.c +++ b/src/cmd/ld/elf64.c @@ -8,20 +8,25 @@ #define NSECT 16 static int numstr; +static int stroffset; static Elf64Hdr hdr; static Elf64PHdr *phdr[NSECT]; static Elf64SHdr *shdr[NSECT]; static char *sname[NSECT]; static char *str[NSECT]; +/* + Initialize the global variable that describes the ELF header. It will be updated as + we write section and prog headers. + */ void elf64init(void) { - hdr.phoff = ELF64HDRSIZE; - hdr.shoff = ELF64HDRSIZE; - hdr.ehsize = ELF64HDRSIZE; - hdr.phentsize = ELF64PHDRSIZE; - hdr.shentsize = ELF64SHDRSIZE; + 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 */ } void @@ -168,3 +173,57 @@ elf64writehdr() WPUT(hdr.shstrndx); return ELF64HDRSIZE; } + +/* Taken directly from the definition document for ELF64 */ +uint32 +elf64_hash(uchar *name) +{ + unsigned long h = 0, g; + while (*name) { + h = (h << 4) + *name++; + if (g = h & 0xf0000000) + h ^= g >> 24; + h &= 0x0fffffff; + } + return h; +} + +void +elf64writedynent(int tag, uint64 val) +{ + VPUT(tag); + VPUT(val); +} + +/* Where to write the next piece of data attached to an SHeader */ +uint64 elfaddr = ELF64FULLHDRSIZE; + +/* Mark a start location in the SHeader data */ +uint64 +startelf(void) +{ + seek(cout, elfaddr, 0); + return elfaddr; +} + +/* Mark the end of a location in the SHeader data */ +uint64 +endelf(void) +{ + uint64 p; + + cflush(); + p = seek(cout, 0, 1); + if (p < elfaddr) { + diag("endelf before elfaddr"); + } + if ((p & 7) != 0) { + p = (p + 7) & ~7LL; + seek(cout, p, 0); + } + elfaddr = p; + if (p > ELF64RESERVE) { + diag("endelf overflows reserve %lld\n", p); + } + return elfaddr; +} diff --git a/src/cmd/ld/elf64.h b/src/cmd/ld/elf64.h index f42ae94252..55d0ca3098 100644 --- a/src/cmd/ld/elf64.h +++ b/src/cmd/ld/elf64.h @@ -121,6 +121,7 @@ struct Elf64PHdr #define PT_DYNAMIC 2 /* Dynamic linking tables */ #define PT_INTERP 3 /* Program interpreter path name */ #define PT_NOTE 4 /* Note sections */ +#define PT_PHDR 6 /* Program header table */ /* P flags */ #define PF_X 0x1 /* Execute permission */ @@ -169,6 +170,103 @@ struct Elf64SHdr #define SHF_MASKOS 0x0F000000 /* Environment-specific use */ #define SHF_MASKPROC 0xF0000000 /* Processor-specific use */ + +typedef struct Elf64Dyn Elf64Dyn; +struct Elf64Dyn +{ + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +}; + +/* Dyn table entries */ +#define DT_NULL 0 /* ignored: Marks the end of the dynamic array */ +#define DT_NEEDED 1 /* d_val: The string table offset of the name of + a needed library. */ +#define DT_PLTRELSZ 2 /* d_val: Total size, in bytes, of the relocation + entries associated with the procedure linkage table. */ +#define DT_PLTGOT 3 /* d_ptr: Contains an address associated with the linkage + table. The specific meaning of this field is + processor-dependent. */ +#define DT_HASH 4 /* d_ptr: Address of the symbol hash table. */ +#define DT_STRTAB 5 /* d_ptr: Address of the dynamic string table. */ +#define DT_SYMTAB 6 /* d_ptr: Address of the dynamic symbol table. */ +#define DT_RELA 7 /* d_ptr Address of a relocation table with Elf64_Rela + entries. */ +#define DT_RELASZ 8 /* d_val: Total size, in bytes, of the DT_RELA relocation + table. */ +#define DT_RELAENT 9 /* d_val: Size, in bytes, of each DT_RELA relocation + entry. */ +#define DT_STRSZ 10 /* d_val: Total size, in bytes, of the string table. */ +#define DT_SYMENT 11 /* d_val: Size, in bytes, of each symbol table entry. */ +#define DT_INIT 12 /* d_ptr Address of the initialization function. */ +#define DT_FINI 13 /* d_ptr Address of the termination function. */ +#define DT_SONAME 14 /* d_val The string table offset of the name of this + shared object. */ +#define DT_RPATH 15 /* d_val The string table offset of a shared library + search path string. */ +#define DT_SYMBOLIC 16 /* ignored The presence of this dynamic table entry + modifies the symbol resolution algorithm for references + within the library. Symbols defined within the library + are used to resolve references before the dynamic + linker searches the usual search path. */ +#define DT_REL 17 /* d_ptr Address of a relocation table with Elf64_Rel + entries. */ +#define DT_RELSZ 18 /* d_val Total size, in bytes, of the DT_REL relocation + table. */ +#define DT_RELENT 19 /* d_val Size, in bytes, of each DT_REL relocation + entry. */ +#define DT_PLTREL 20 /* d_val Type of relocation entry used for the procedure + linkage table. The d_val member contains either DT_REL + or DT_RELA. */ +#define DT_DEBUG 21 /* d_ptr Reserved for debugger use. */ +#define DT_TEXTREL 22 /* ignored The presence of this dynamic table entry + signals that the relocation table contains relocations + for a non-writable segment. */ +#define DT_JMPREL 23 /* d_ptr Address of the relocations associated with the + procedure linkage table. */ +#define DT_BIND_NOW 24 /* ignored The presence of this dynamic table entry + signals that the dynamic loader should process all + relocations for this object before transferring + control to the program. */ +#define DT_INIT_ARRAY 25 /* d_ptr Pointer to an array of pointers to initialization + functions. */ +#define DT_FINI_ARRAY 26 /* d_ptr Pointer to an array of pointers to termination + functions. */ +#define DT_INIT_ARRAYSZ 27 /* d_val Size, in bytes, of the array of initialization + functions. */ +#define DT_FINI_ARRAYSZ 28 /* d_val Size, in bytes, of the array of termination + functions. */ +#define DT_LOOS 0x60000000 /* Defines a range of dynamic table tags that are reserved + for environment-specific use. */ +#define DT_HIOS 0x6FFFFFFF +#define DT_LOPROC 0x70000000 /* Defines a range of dynamic table tags that are + reserved for processor-specific use. */ +#define DT_HIPROC 0x7FFFFFFF + +typedef struct Elf64_Rel Elf64_Rel; +struct Elf64_Rel +{ + Elf64_Addr r_offset; /* Address of reference */ + Elf64_Xword r_info; /* Symbol index and type of relocation */ +}; +#define ELF64RELSIZE 8 + +typedef struct Elf64_Rela Elf64_Rela; +struct Elf64_Rela +{ + Elf64_Addr r_offset; /* Address of reference */ + Elf64_Xword r_info; /* Symbol index and type of relocation */ + Elf64_Sxword r_addend; /* Constant part of expression */ +}; +#define ELF64RELASIZE 24 + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffffL) +#define ELF64_R_INFO(s, t) (((s) << 32) + ((t) & 0xffffffffL)) + void elf64init(void); Elf64Hdr *getElf64Hdr(); Elf64SHdr *newElf64SHdr(char*); @@ -177,10 +275,17 @@ uint32 elf64writehdr(void); uint32 elf64writephdrs(void); uint32 elf64writeshdrs(void); void elf64writestrtable(void); - +void elf64writedynent(int, uint64); +uint32 elf64_hash(uchar*); +uint64 startelf(void); +uint64 endelf(void); extern int nume64phdr; extern int nume64shdr; #define STRTABSIZE 256 -/* Amount of space to reserve at the start of the file; may waste some */ +/* Amount of space available for Header, PHeaders and SHeaders */ #define ELF64FULLHDRSIZE 2048 +/* Space reserved after ELF64FULLHEADERSIZE for dynamic info */ +#define ELFDYNAMICSIZE 256 +/* Total amount of ELF space to reserve at the start of the file; may waste some */ +#define ELF64RESERVE 4096