Commit 3d42e691 authored by Rob Pike's avatar Rob Pike

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
parent ff790f47
......@@ -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();
......
......@@ -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;
......
......@@ -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)
......
......@@ -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;
}
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment