summaryrefslogtreecommitdiff
path: root/libdynld
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libdynld
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libdynld')
-rw-r--r--libdynld/NOTICE28
-rw-r--r--libdynld/dynld-386.c42
-rw-r--r--libdynld/dynld-68000.c22
-rw-r--r--libdynld/dynld-arm.c44
-rw-r--r--libdynld/dynld-mips.c22
-rw-r--r--libdynld/dynld-power.c65
-rw-r--r--libdynld/dynld-sparc.c20
-rw-r--r--libdynld/dynld.c258
-rw-r--r--libdynld/dynloadfd.c35
-rw-r--r--libdynld/mkfile12
10 files changed, 548 insertions, 0 deletions
diff --git a/libdynld/NOTICE b/libdynld/NOTICE
new file mode 100644
index 00000000..b90dffa1
--- /dev/null
+++ b/libdynld/NOTICE
@@ -0,0 +1,28 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ Copyright © 2004-2006 Vita Nuova Holdings Limited (www.vitanuova.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/libdynld/dynld-386.c b/libdynld/dynld-386.c
new file mode 100644
index 00000000..040111d3
--- /dev/null
+++ b/libdynld/dynld-386.c
@@ -0,0 +1,42 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | I_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ int i;
+ ulong v, *pp;
+
+ p += (ulong)b;
+ pp = (ulong*)p;
+ v = *pp;
+ switch(m){
+ case 0:
+ v += (ulong)b;
+ break;
+ case 1:
+ i = v>>22;
+ v &= 0x3fffff;
+ CHK(i, ntab);
+ v += tab[i]->addr;
+ break;
+ case 2:
+ i = v>>22;
+ CHK(i, ntab);
+ v = tab[i]->addr -p-4;
+ break;
+ default:
+ return "bad relocation mode";
+ }
+ *pp = v;
+ return nil;
+}
diff --git a/libdynld/dynld-68000.c b/libdynld/dynld-68000.c
new file mode 100644
index 00000000..db907983
--- /dev/null
+++ b/libdynld/dynld-68000.c
@@ -0,0 +1,22 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | A_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ USED(b);
+ USED(p);
+ USED(m);
+ USED(tab);
+ USED(ntab);
+ return "68000 unimplemented";
+}
diff --git a/libdynld/dynld-arm.c b/libdynld/dynld-arm.c
new file mode 100644
index 00000000..a6654751
--- /dev/null
+++ b/libdynld/dynld-arm.c
@@ -0,0 +1,44 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | E_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ int i;
+ ulong v, *pp;
+
+ p <<= 2;
+ p += (ulong)b;
+ pp = (ulong*)p;
+ v = *pp;
+ switch(m){
+ case 0:
+ v += (ulong)b;
+ break;
+ case 1:
+ i = v>>22;
+ v &= 0x3fffff;
+ CHK(i, ntab);
+ v += tab[i]->addr;
+ break;
+ case 2:
+ i = v&0x3ff;
+ v &= ~0x3ff;
+ CHK(i, ntab);
+ v |= ((tab[i]->addr-p-8)>>2)&0xffffff;
+ break;
+ default:
+ return "invalid relocation mode";
+ }
+ *pp = v;
+ return nil;
+}
diff --git a/libdynld/dynld-mips.c b/libdynld/dynld-mips.c
new file mode 100644
index 00000000..630a5d5f
--- /dev/null
+++ b/libdynld/dynld-mips.c
@@ -0,0 +1,22 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | V_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ USED(b);
+ USED(p);
+ USED(m);
+ USED(tab);
+ USED(ntab);
+ return "mips unimplemented";
+}
diff --git a/libdynld/dynld-power.c b/libdynld/dynld-power.c
new file mode 100644
index 00000000..5f2860d1
--- /dev/null
+++ b/libdynld/dynld-power.c
@@ -0,0 +1,65 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | Q_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ int i;
+ ulong v, *pp0, *pp1;
+
+ p <<= 2;
+ p += (ulong)b;
+ pp0 = (ulong*)p;
+ v = *pp0;
+ switch(m){
+ case 0:
+ v += (ulong)b;
+ break;
+ case 1:
+ i = v>>22;
+ v &= 0x3fffff;
+ CHK(i, ntab);
+ v += tab[i]->addr;
+ break;
+ case 2:
+ i = (v&0xffc)>>2;
+ v &= ~0xffc;
+ CHK(i, ntab);
+ v |= (tab[i]->addr-p)&0x3fffffc;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ pp1 = (ulong*)(p+4);
+ v = (v<<16)|(*pp1&0xffff);
+ if(m&1)
+ v += (ulong)b;
+ else{
+ i = v>>22;
+ v &= 0x3fffff;
+ CHK(i, ntab);
+ v += tab[i]->addr;
+ }
+ if(m >= 5 && (v&0x8000))
+ v += 0x10000;
+ *pp0 &= ~0xffff;
+ *pp0 |= v>>16;
+ *pp1 &= ~0xffff;
+ *pp1 |= v&0xffff;
+ return nil;
+ default:
+ return "invalid relocation mode";
+ }
+ *pp0 = v;
+ return nil;
+}
diff --git a/libdynld/dynld-sparc.c b/libdynld/dynld-sparc.c
new file mode 100644
index 00000000..4f8dd2f5
--- /dev/null
+++ b/libdynld/dynld-sparc.c
@@ -0,0 +1,20 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | K_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ USED(b);
+ USED(p);
+ USED(m);
+ USED(tab);
+ USED(ntab);
+ return "sparc unimplemented";
+}
diff --git a/libdynld/dynld.c b/libdynld/dynld.c
new file mode 100644
index 00000000..43bef93c
--- /dev/null
+++ b/libdynld/dynld.c
@@ -0,0 +1,258 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+static ulong
+get2(uchar *b)
+{
+ return (b[0] << 8) | b[1];
+}
+
+static ulong
+get4(uchar *b)
+{
+ return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
+}
+
+static ulong
+lgetbe(ulong l)
+{
+ union {
+ ulong l;
+ uchar c[4];
+ } u;
+ u.l = l;
+ return get4(u.c);
+}
+
+Dynsym*
+dynfindsym(char *s, Dynsym *tab, int ntab)
+{
+ int n, n2, d;
+ Dynsym *t, *m;
+
+ t = tab;
+ n = ntab;
+ while(n > 0){
+ n2 = n>>1;
+ m = t+n2;
+ d = strcmp(s, m->name);
+ if(d < 0){
+ n = n2;
+ continue;
+ }
+ if(d > 0){
+ t = m+1;
+ n -= n2+1;
+ continue;
+ }
+ return m;
+ }
+ return nil;
+}
+
+void*
+dynimport(Dynobj *o, char *name, ulong sig)
+{
+ Dynsym *t;
+
+ t = dynfindsym(name, o->export, o->nexport);
+ if(t == nil || sig != 0 && t->sig != 0 && t->sig != sig)
+ return nil;
+ return (void*)t->addr;
+}
+
+int
+dyntabsize(Dynsym *t)
+{
+ int n;
+
+ for(n = 0; t->name != nil; t++)
+ n++;
+ return n;
+}
+
+void
+dynobjfree(Dynobj *o)
+{
+ if(o != nil){
+ free(o->base);
+ free(o->import);
+ free(o);
+ }
+}
+
+void
+dynfreeimport(Dynobj *o)
+{
+ free(o->import);
+ o->import = nil;
+ o->nimport = 0;
+}
+
+static char Ereloc[] = "error reading object file";
+
+Dynobj*
+dynloadgen(void *file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int), void (*werr)(char*), Dynsym *tab, int ntab, ulong maxsize)
+{
+ int i, m, n, ni, nr, relsize;
+ ulong syms, entry, sig, p, a;
+ uchar *base;
+ Exec e;
+ Dynsym *t;
+ Dynobj *l;
+ char *s, *err, buf[64];
+ uchar *reldata, *rp, *ep;
+ vlong off;
+
+ err = Ereloc; /* default */
+ off = (*sk)(file, 0, 1);
+ l = mallocz(sizeof(Dynobj), 1);
+ if(l == nil){
+ err = "can't allocate Dynobj";
+ goto Error;
+ }
+ if((*rd)(file, &e, sizeof(Exec)) != sizeof(Exec))
+ goto Error;
+ if(lgetbe(e.magic) != dynmagic()){
+ err = "not dynamic object file or wrong platform";
+ goto Error;
+ }
+ l->text = lgetbe(e.text);
+ l->data = lgetbe(e.data);
+ l->bss = lgetbe(e.bss);
+ syms = lgetbe(e.syms)+lgetbe(e.spsz)+lgetbe(e.pcsz);
+ entry = lgetbe(e.entry);
+ l->size = l->text + l->data + l->bss;
+ if(entry < 0 || entry >= l->size || entry & 3){
+ err = "invalid export table pointer (entry point)";
+ goto Error;
+ }
+ if(maxsize && l->size >= maxsize){
+ snprint(buf, sizeof(buf), "%lud: object too big", l->size);
+ err = buf;
+ goto Error;
+ }
+
+ l->base = base = malloc(l->size);
+ if(base == nil){
+ err = "out of memory: loading object file";
+ goto Error;
+ }
+ l->export = (Dynsym*)(base+entry);
+ if((*rd)(file, base, l->text+l->data) != l->text+l->data)
+ goto Error;
+ memset(base+l->text+l->data, 0, l->bss);
+ if((*sk)(file, syms, 1) < 0)
+ goto Error;
+ if((*rd)(file, buf, 4) != 4)
+ goto Error;
+ relsize = get4((uchar*)buf); /* always contains at least an import count (might be zero) */
+ if(relsize < 4)
+ goto Error;
+ reldata = malloc(relsize);
+ if(reldata == nil){
+ err = "out of memory: relocation data";
+ goto Error;
+ }
+ if((*rd)(file, reldata, relsize) != relsize)
+ goto Error;
+ rp = reldata;
+ ep = reldata+relsize;
+ ni = get4(rp);
+ rp += 4;
+ if(ni < 0 || ni > 8000)
+ goto Error; /* implausible size */
+ l->nimport = ni;
+ l->import = malloc(ni*sizeof(Dynsym*));
+ if(l->import == nil){
+ err = "out of memory: symbol table";
+ goto Error;
+ }
+ for(i = 0; i < ni; i++){
+ if(rp+5 > ep)
+ goto Error;
+ sig = get4(rp);
+ rp += 4;
+ s = (char*)rp;
+ while(*rp++)
+ if(rp >= ep)
+ goto Error;
+ t = dynfindsym(s, tab, ntab);
+ if(t == nil){
+ snprint(buf, sizeof(buf), "undefined symbol: %s", s);
+ err = buf;
+ goto Error;
+ }
+ if(sig != 0 && t->sig != 0 && t->sig != sig){
+ snprint(buf, sizeof(buf), "signature mismatch: %s (%lux != %lux)", s, sig, t->sig);
+ err = buf;
+ goto Error;
+ }
+ l->import[i] = t;
+ }
+
+ a = 0;
+ if(rp+4 > ep)
+ goto Error;
+ nr = get4(rp);
+ rp += 4;
+ for(i = 0; i < nr; i++){
+ if(rp >= ep)
+ goto Error;
+ m = *rp++;
+ n = m>>6;
+ if(rp+(1<<n) > ep)
+ goto Error;
+ switch(n){
+ case 0:
+ p = *rp++;
+ break;
+ case 1:
+ p = get2(rp);
+ rp += 2;
+ break;
+ case 2:
+ p = get4(rp);
+ rp += 4;
+ break;
+ default:
+ goto Error;
+ }
+ a += p;
+ err = dynreloc(base, a, m&0xf, l->import, ni);
+ if(err != nil){
+ snprint(buf, sizeof(buf), "dynamic object: %s", err);
+ err = buf;
+ goto Error;
+ }
+ }
+ free(reldata);
+
+ /* could check relocated export table here */
+ l->nexport = dyntabsize(l->export);
+
+ segflush(base, l->text);
+
+ return l;
+
+Error:
+ if(off >= 0)
+ (*sk)(file, off, 0); /* restore original file offset */
+ (*werr)(err);
+ dynobjfree(l);
+ return nil;
+}
+
+int
+dynloadable(void* file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int))
+{
+ long magic;
+
+ if((*rd)(file, &magic, sizeof(magic)) != sizeof(magic)){
+ (*sk)(file, -(signed int)sizeof(magic), 1);
+ return 0;
+ }
+ (*sk)(file, -(signed int)sizeof(magic), 1);
+ return lgetbe(magic) == dynmagic();
+}
diff --git a/libdynld/dynloadfd.c b/libdynld/dynloadfd.c
new file mode 100644
index 00000000..1241cffc
--- /dev/null
+++ b/libdynld/dynloadfd.c
@@ -0,0 +1,35 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+typedef struct Fd Fd;
+struct Fd {
+ int fd;
+};
+
+static long
+readfd(void *a, void *buf, long nbytes)
+{
+ return read(((Fd*)a)->fd, buf, nbytes);
+}
+
+static vlong
+seekfd(void *a, vlong off, int t)
+{
+ return seek(((Fd*)a)->fd, off, t);
+}
+
+static void
+errfd(char *s)
+{
+ werrstr("%s", s);
+}
+
+Dynobj*
+dynloadfd(int fd, Dynsym *sym, int nsym, ulong maxsize)
+{
+ Fd f;
+
+ f.fd = fd;
+ return dynloadgen(&f, readfd, seekfd, errfd, sym, nsym, maxsize);
+}
diff --git a/libdynld/mkfile b/libdynld/mkfile
new file mode 100644
index 00000000..53ea179d
--- /dev/null
+++ b/libdynld/mkfile
@@ -0,0 +1,12 @@
+<../mkconfig
+
+LIB=libdynld.a
+
+OFILES=\
+ dynld-$OBJTYPE.$O\
+ dynloadfd.$O\
+ dynld.$O\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/lib9.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE