summaryrefslogtreecommitdiff
path: root/utils/ld/elf.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/ld/elf.c')
-rw-r--r--utils/ld/elf.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/utils/ld/elf.c b/utils/ld/elf.c
new file mode 100644
index 00000000..2b25c57c
--- /dev/null
+++ b/utils/ld/elf.c
@@ -0,0 +1,266 @@
+/*
+ * emit 32- or 64-bit elf headers for any architecture.
+ * this is a component of ?l.
+ */
+#include "l.h"
+
+enum {
+ /* offsets into string table */
+ Stitext = 1,
+ Stidata = 7,
+ Stistrtab = 13,
+};
+
+void
+elfident(int bo, int class)
+{
+ strnput("\177ELF", 4); /* e_ident */
+ cput(class);
+ cput(bo); /* byte order */
+ cput(1); /* version = CURRENT */
+ if(debug['k']){ /* boot/embedded/standalone */
+ cput(255);
+ cput(0);
+ }
+ else{
+ cput(0); /* osabi = SYSV */
+ cput(0); /* abiversion = 3 */
+ }
+ strnput("", 7);
+}
+
+void
+elfstrtab(void)
+{
+ /* string table */
+ cput(0);
+ strnput(".text", 5); /* +1 */
+ cput(0);
+ strnput(".data", 5); /* +7 */
+ cput(0);
+ strnput(".strtab", 7); /* +13 */
+ cput(0);
+ cput(0);
+}
+
+void
+elf32phdr(void (*putl)(long), ulong type, ulong off, ulong vaddr, ulong paddr,
+ ulong filesz, ulong memsz, ulong prots, ulong align)
+{
+ putl(type);
+ putl(off);
+ putl(vaddr);
+ putl(paddr);
+ putl(filesz);
+ putl(memsz);
+ putl(prots);
+ putl(align);
+}
+
+void
+elf32shdr(void (*putl)(long), ulong name, ulong type, ulong flags, ulong vaddr,
+ ulong off, ulong sectsz, ulong link, ulong addnl, ulong align,
+ ulong entsz)
+{
+ putl(name);
+ putl(type);
+ putl(flags);
+ putl(vaddr);
+ putl(off);
+ putl(sectsz);
+ putl(link);
+ putl(addnl);
+ putl(align);
+ putl(entsz);
+}
+
+static void
+elf32sectab(void (*putl)(long))
+{
+ seek(cout, HEADR+textsize+datsize+symsize, 0);
+ elf32shdr(putl, Stitext, Progbits, Salloc|Sexec, INITTEXT,
+ HEADR, textsize, 0, 0, 0x10000, 0);
+ elf32shdr(putl, Stidata, Progbits, Salloc|Swrite, INITDAT,
+ HEADR+textsize, datsize, 0, 0, 0x10000, 0);
+ elf32shdr(putl, Stistrtab, Strtab, 1 << 5, 0,
+ HEADR+textsize+datsize+symsize+3*Shdr32sz, 14, 0, 0, 1, 0);
+ elfstrtab();
+}
+
+/* if addpsects > 0, putpsects must emit exactly that many psects. */
+void
+elf32(int mach, int bo, int addpsects, void (*putpsects)(Putl))
+{
+ ulong phydata;
+ void (*putw)(long), (*putl)(long);
+
+ if(bo == ELFDATA2MSB){
+ putw = wput;
+ putl = lput;
+ }else if(bo == ELFDATA2LSB){
+ putw = wputl;
+ putl = lputl;
+ }else{
+ print("elf32 byte order is mixed-endian\n");
+ errorexit();
+ return;
+ }
+
+ elfident(bo, ELFCLASS32);
+ putw(EXEC);
+ putw(mach);
+ putl(1L); /* version = CURRENT */
+ putl(entryvalue()); /* entry vaddr */
+ putl(Ehdr32sz); /* offset to first phdr */
+ if(debug['S'])
+ putl(HEADR+textsize+datsize+symsize); /* offset to first shdr */
+ else
+ putl(0);
+ putl(0L); /* flags */
+ putw(Ehdr32sz);
+ putw(Phdr32sz);
+ putw(3 + addpsects); /* # of Phdrs */
+ putw(Shdr32sz);
+ if(debug['S']){
+ putw(3); /* # of Shdrs */
+ putw(2); /* Shdr table index */
+ }else{
+ putw(0);
+ putw(0);
+ }
+
+ /*
+ * could include ELF headers in text -- 8l doesn't,
+ * but in theory it aids demand loading.
+ */
+ elf32phdr(putl, PT_LOAD, HEADR, INITTEXT, INITTEXTP,
+ textsize, textsize, R|X, INITRND); /* text */
+ /*
+ * we need INITDATP, but it has to be computed.
+ * assume distance between INITTEXT & INITTEXTP is also
+ * correct for INITDAT and INITDATP.
+ */
+ phydata = INITDAT - (INITTEXT - INITTEXTP);
+ elf32phdr(putl, PT_LOAD, HEADR+textsize, INITDAT, phydata,
+ datsize, datsize+bsssize, R|W|X, INITRND); /* data */
+ elf32phdr(putl, NOPTYPE, HEADR+textsize+datsize, 0, 0,
+ symsize, lcsize, R, 4); /* symbol table */
+ if (addpsects > 0)
+ putpsects(putl);
+ cflush();
+
+ if(debug['S'])
+ elf32sectab(putl);
+}
+
+/*
+ * elf64
+ */
+
+void
+elf64phdr(void (*putl)(long), void (*putll)(vlong), ulong type, uvlong off,
+ uvlong vaddr, uvlong paddr, uvlong filesz, uvlong memsz, ulong prots,
+ uvlong align)
+{
+ putl(type);
+ putl(prots);
+ putll(off);
+ putll(vaddr);
+ putll(paddr);
+ putll(filesz);
+ putll(memsz);
+ putll(align);
+}
+
+void
+elf64shdr(void (*putl)(long), void (*putll)(vlong), ulong name, ulong type,
+ uvlong flags, uvlong vaddr, uvlong off, uvlong sectsz, ulong link,
+ ulong addnl, uvlong align, uvlong entsz)
+{
+ putl(name);
+ putl(type);
+ putll(flags);
+ putll(vaddr);
+ putll(off);
+ putll(sectsz);
+ putl(link);
+ putl(addnl);
+ putll(align);
+ putll(entsz);
+}
+
+static void
+elf64sectab(void (*putl)(long), void (*putll)(vlong))
+{
+ seek(cout, HEADR+textsize+datsize+symsize, 0);
+ elf64shdr(putl, putll, Stitext, Progbits, Salloc|Sexec, INITTEXT,
+ HEADR, textsize, 0, 0, 0x10000, 0);
+ elf64shdr(putl, putll, Stidata, Progbits, Salloc|Swrite, INITDAT,
+ HEADR+textsize, datsize, 0, 0, 0x10000, 0);
+ elf64shdr(putl, putll, Stistrtab, Strtab, 1 << 5, 0,
+ HEADR+textsize+datsize+symsize+3*Shdr64sz, 14, 0, 0, 1, 0);
+ elfstrtab();
+}
+
+/* if addpsects > 0, putpsects must emit exactly that many psects. */
+void
+elf64(int mach, int bo, int addpsects, void (*putpsects)(Putl))
+{
+ uvlong phydata;
+ void (*putw)(long), (*putl)(long);
+ void (*putll)(vlong);
+
+ if(bo == ELFDATA2MSB){
+ putw = wput;
+ putl = lput;
+ putll = llput;
+ }else if(bo == ELFDATA2LSB){
+ putw = wputl;
+ putl = lputl;
+ putll = llputl;
+ }else{
+ print("elf64 byte order is mixed-endian\n");
+ errorexit();
+ return;
+ }
+
+ elfident(bo, ELFCLASS64);
+ putw(EXEC);
+ putw(mach);
+ putl(1L); /* version = CURRENT */
+ putll(entryvalue()); /* entry vaddr */
+ putll(Ehdr64sz); /* offset to first phdr */
+ if(debug['S'])
+ putll(HEADR+textsize+datsize+symsize); /* offset to 1st shdr */
+ else
+ putll(0);
+ putl(0L); /* flags */
+ putw(Ehdr64sz);
+ putw(Phdr64sz);
+ putw(3 + addpsects); /* # of Phdrs */
+ putw(Shdr64sz);
+ if(debug['S']){
+ putw(3); /* # of Shdrs */
+ putw(2); /* Shdr table index */
+ }else{
+ putw(0);
+ putw(0);
+ }
+
+ elf64phdr(putl, putll, PT_LOAD, HEADR, INITTEXT, INITTEXTP,
+ textsize, textsize, R|X, INITRND); /* text */
+ /*
+ * see 32-bit ELF case for physical data address computation.
+ */
+ phydata = INITDAT - (INITTEXT - INITTEXTP);
+ elf64phdr(putl, putll, PT_LOAD, HEADR+textsize, INITDAT, phydata,
+ datsize, datsize+bsssize, R|W, INITRND); /* data */
+ elf64phdr(putl, putll, NOPTYPE, HEADR+textsize+datsize, 0, 0,
+ symsize, lcsize, R, 4); /* symbol table */
+ if (addpsects > 0)
+ putpsects(putl);
+ cflush();
+
+ if(debug['S'])
+ elf64sectab(putl, putll);
+}