summaryrefslogtreecommitdiff
path: root/utils/ld
diff options
context:
space:
mode:
Diffstat (limited to 'utils/ld')
-rw-r--r--utils/ld/Nt.c100
-rw-r--r--utils/ld/Plan9.c66
-rw-r--r--utils/ld/Posix.c89
-rw-r--r--utils/ld/elf.c266
4 files changed, 521 insertions, 0 deletions
diff --git a/utils/ld/Nt.c b/utils/ld/Nt.c
new file mode 100644
index 00000000..938664c2
--- /dev/null
+++ b/utils/ld/Nt.c
@@ -0,0 +1,100 @@
+#include <windows.h>
+
+/*
+ * We can't include l.h, because Windoze wants to use some names
+ * like FLOAT and ABC which we declare. Define what we need here.
+ */
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+extern char *hunk;
+extern long nhunk;
+
+void gethunk(void);
+
+/*
+ * fake malloc
+ */
+void*
+malloc(uint n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+}
+
+void*
+calloc(uint m, uint n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, uint n)
+{
+ void *new;
+
+ new = malloc(n);
+ if(new && p)
+ memmove(new, p, n);
+ return new;
+}
+
+#define Chunk (1*1024*1024)
+
+void*
+mysbrk(ulong size)
+{
+ void *v;
+ static int chunk;
+ static uchar *brk;
+
+ if(chunk < size) {
+ chunk = Chunk;
+ if(chunk < size)
+ chunk = Chunk + size;
+ brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if(brk == 0)
+ return (void*)-1;
+ }
+ v = brk;
+ chunk -= size;
+ brk += size;
+ return v;
+}
+
+double
+cputime(void)
+{
+ return ((double)0);
+}
+
+int
+fileexists(char *name)
+{
+ int fd;
+
+ fd = open(f, OREAD);
+ if(fd < 0)
+ return 0;
+ close(fd);
+ return 1;
+}
diff --git a/utils/ld/Plan9.c b/utils/ld/Plan9.c
new file mode 100644
index 00000000..ef08b158
--- /dev/null
+++ b/utils/ld/Plan9.c
@@ -0,0 +1,66 @@
+#include "l.h"
+
+/*
+ * fake malloc
+ */
+void*
+malloc(ulong n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, ulong n)
+{
+ USED(p);
+ USED(n);
+ fprint(2, "realloc called\n");
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return sbrk(size);
+}
+
+void
+setmalloctag(void*, ulong)
+{
+}
+
+int
+fileexists(char *s)
+{
+ uchar dirbuf[400];
+
+ /* it's fine if stat result doesn't fit in dirbuf, since even then the file exists */
+ return stat(s, dirbuf, sizeof(dirbuf)) >= 0;
+}
diff --git a/utils/ld/Posix.c b/utils/ld/Posix.c
new file mode 100644
index 00000000..a1a2a8c9
--- /dev/null
+++ b/utils/ld/Posix.c
@@ -0,0 +1,89 @@
+#include "l.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/times.h>
+#undef getwd
+#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */
+
+/*
+ * fake malloc
+ */
+void*
+malloc(size_t n)
+{
+ void *p;
+
+ while(n & 7)
+ n++;
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void
+free(void *p)
+{
+ USED(p);
+}
+
+void*
+calloc(size_t m, size_t n)
+{
+ void *p;
+
+ n *= m;
+ p = malloc(n);
+ memset(p, 0, n);
+ return p;
+}
+
+void*
+realloc(void *p, size_t n)
+{
+ fprint(2, "realloc called\n", p, n);
+ abort();
+ return 0;
+}
+
+void*
+mysbrk(ulong size)
+{
+ return (void*)sbrk(size);
+}
+
+double
+cputime(void)
+{
+
+ struct tms tmbuf;
+ double ret_val;
+
+ /*
+ * times() only fails if &tmbuf is invalid.
+ */
+ (void)times(&tmbuf);
+ /*
+ * Return the total time (in system clock ticks)
+ * spent in user code and system
+ * calls by both the calling process and its children.
+ */
+ ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime +
+ tmbuf.tms_cutime + tmbuf.tms_cstime);
+ /*
+ * Convert to seconds.
+ */
+ ret_val *= sysconf(_SC_CLK_TCK);
+ return ret_val;
+
+}
+
+int
+fileexists(char *name)
+{
+ struct stat sb;
+
+ return stat(name, &sb) >= 0;
+}
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);
+}