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
#define PADDR(a) ((uint32)(a) & ~0x80000000)
+char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
+
+char zeroes[32];
+
vlong
entryvalue(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());
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;
}
/* 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);
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");
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';
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();
}
cflush();
- /* string table */
- seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
- elf64writestrtable();
- cflush();
-
break;
}
cflush();
EXTERN int exports, nexports;
EXTERN char* EXPTAB;
EXTERN Prog undefp;
-EXTERN uint32 stroffset;
EXTERN vlong textstksiz;
EXTERN vlong textarg;
INITRND = 4096;
break;
case 7: /* elf64 executable */
- HEADR = ELF64FULLHDRSIZE;
+ HEADR = ELF64RESERVE;
if(INITTEXT == -1)
INITTEXT = (1<<22)+HEADR;
if(INITDAT == -1)
#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
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;
+}
#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 */
#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*);
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