From 37da2899f40661e3e9631e497da8dc59b971cbd0 Mon Sep 17 00:00:00 2001 From: "Charles.Forsyth" Date: Fri, 22 Dec 2006 17:07:39 +0000 Subject: 20060303a --- libdynld/NOTICE | 28 ++++++ libdynld/dynld-386.c | 42 ++++++++ libdynld/dynld-68000.c | 22 +++++ libdynld/dynld-arm.c | 44 +++++++++ libdynld/dynld-mips.c | 22 +++++ libdynld/dynld-power.c | 65 +++++++++++++ libdynld/dynld-sparc.c | 20 ++++ libdynld/dynld.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++ libdynld/dynloadfd.c | 35 +++++++ libdynld/mkfile | 12 +++ 10 files changed, 548 insertions(+) create mode 100644 libdynld/NOTICE create mode 100644 libdynld/dynld-386.c create mode 100644 libdynld/dynld-68000.c create mode 100644 libdynld/dynld-arm.c create mode 100644 libdynld/dynld-mips.c create mode 100644 libdynld/dynld-power.c create mode 100644 libdynld/dynld-sparc.c create mode 100644 libdynld/dynld.c create mode 100644 libdynld/dynloadfd.c create mode 100644 libdynld/mkfile (limited to 'libdynld') 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 +#include + +#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 +#include + +#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 +#include + +#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 +#include + +#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 +#include + +#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 +#include + +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 +#include + +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< 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 +#include + +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 -- cgit v1.2.3