diff --git a/sys/include/ape/dynld.h b/sys/include/ape/dynld.h new file mode 100644 index 0000000..03261d3 --- /dev/null +++ b/sys/include/ape/dynld.h @@ -0,0 +1,49 @@ +#ifndef __DYNLD_H +#define __DYNLD_H +#if !defined(_PLAN9_SOURCE) + This header file is an extension to ANSI/POSIX +#endif + +#pragma src "/sys/src/ape/lib/dynld" +#pragma lib "/$M/lib/ape/libdynld.a" + +typedef struct Dynobj Dynobj; +typedef struct Dynsym Dynsym; + +struct Dynobj +{ + unsigned long size; /* total size in bytes */ + unsigned long text; /* bytes of text */ + unsigned long data; /* bytes of data */ + unsigned long bss; /* bytes of bss */ + unsigned char* base; /* start of text, data, bss */ + int nexport; + Dynsym* export; /* export table */ + int nimport; + Dynsym** import; /* import table */ +}; + +/* + * this structure is known to the linkers + */ +struct Dynsym +{ + unsigned long sig; + unsigned long addr; + char *name; +}; + +extern Dynsym* dynfindsym(char*, Dynsym*, int); +extern void dynfreeimport(Dynobj*); +extern void* dynimport(Dynobj*, char*, unsigned long); +extern int dynloadable(void*, long (*r)(void*,void*,long), long long(*sk)(void*,long long,int)); +extern Dynobj* dynloadfd(int, Dynsym*, int, unsigned long); +extern Dynobj* dynloadgen(void*, long (*r)(void*,void*,long), long long (*s)(void*,long long,int), void (*e)(char*), Dynsym*, int, unsigned long); +extern long dynmagic(void); +extern void dynobjfree(Dynobj*); +extern char* dynreloc(unsigned char*, unsigned long, int, Dynsym**, int); +extern int dyntabsize(Dynsym*); + +extern Dynsym _exporttab[]; /* created by linker -x (when desired) */ + +#endif diff --git a/sys/include/dynld.h b/sys/include/dynld.h new file mode 100644 index 0000000..eeac1c2 --- /dev/null +++ b/sys/include/dynld.h @@ -0,0 +1,41 @@ +#pragma src "/sys/src/libdynld" +#pragma lib "libdynld.a" + +typedef struct Dynobj Dynobj; +typedef struct Dynsym Dynsym; + +struct Dynobj +{ + ulong size; /* total size in bytes */ + ulong text; /* bytes of text */ + ulong data; /* bytes of data */ + ulong bss; /* bytes of bss */ + uchar* base; /* start of text, data, bss */ + int nexport; + Dynsym* export; /* export table */ + int nimport; + Dynsym** import; /* import table */ +}; + +/* + * this structure is known to the linkers + */ +struct Dynsym +{ + ulong sig; + ulong addr; + char *name; +}; + +extern Dynsym* dynfindsym(char*, Dynsym*, int); +extern void dynfreeimport(Dynobj*); +extern void* dynimport(Dynobj*, char*, ulong); +extern int dynloadable(void*, long (*r)(void*,void*,long), vlong(*sk)(void*,vlong,int)); +extern Dynobj* dynloadfd(int, Dynsym*, int, ulong); +extern Dynobj* dynloadgen(void*, long (*r)(void*,void*,long), vlong (*s)(void*,vlong,int), void (*e)(char*), Dynsym*, int, ulong); +extern long dynmagic(void); +extern void dynobjfree(Dynobj*); +extern char* dynreloc(uchar*, ulong, int, Dynsym**, int); +extern int dyntabsize(Dynsym*); + +extern Dynsym _exporttab[]; /* created by linker -x (when desired) */ diff --git a/sys/man/2/dynld b/sys/man/2/dynld new file mode 100644 index 0000000..8977333 --- /dev/null +++ b/sys/man/2/dynld @@ -0,0 +1,287 @@ +.TH DYNLD 2 +.SH NAME +dynfindsym, dynfreeimport, dynloadfd, dynloadgen, dynobjfree, dyntabsize \- load object file dynamically +.SH SYNOPSIS +.B #include +.br +.B #include +.br +.B #include +.PP +.ta \w'\fLDynsym*** 'u +.B +Dynsym* dynfindsym(char *name, Dynsym *syms, int nsym) +.PP +.B +Dynobj* dynloadfd(int fd, Dynsym *exports, int nexport, +.br +.B + ulong maxsize) +.PP +.B +Dynobj* dynloadgen(void *file, long (*read)(void*,void*,long), +.br +.B + vlong (*seek)(void*,vlong,int), void (*err)(char*), +.br +.B + Dynsym *exports, int nexport, ulong maxsize) +.PP +.B +void* dynimport(Dynobj *o, char *name, ulong sig) +.PP +.B +void dynfreeimport(Dynobj *o) +.PP +.B +void dynobjfree(Dynobj *o) +.PP +.B +int dyntabsize(Dynsym *t) +.PP +.B +extern Dynsym _exporttab[]; +.DT +.SH DESCRIPTION +These functions allow a process to load further code and data +into the currently executing image. +A dynamically-loadable file, called a +.I module +here, is a variant of the +.IR a.out (10.6) +executable format with some extra components. +The loader for the architecture +(see +.IR 8l (1)) +creates a module file from component object file(s) when given the +.B -u +option. +A module contains text and data sections, an import table, an export table, +and relocation data. +The import table lists the symbols the module needs from the loading program; +the export table lists symbols the module provides when loaded. +A program that loads a module provides a table of its own symbols to match +the symbols in the module's import table. +.PP +A symbol entry in a symbol table names a global function or data item, and has an associated +.I signature +value representing the type of the corresponding function or data in the source code. +The +.B Dynsym +structure defines a symbol: +.IP +.EX +typedef struct { + ulong sig; + ulong addr; + char* name; +} Dynsym; +.EE +.PP +The structure is known to the loaders +.IR 8l (1). +.I Name +is the linkage name of the function or data. +.I Addr +is its address, which is relative to the start of the module before loading, +and an address in the current address space after loading. +The signature +.I sig +is the value produced by the C compiler's +.B signof +operator applied to the type. +Symbol tables must be sorted by +.IR name . +.PP +An executable that wishes to load modules will normally be linked using the +.B -x +option to the appropriate loader +.IR 8l (1). +The resulting executable contains an export table +.B _exporttab +that lists all the exported symbols of the program (by default, all external symbols). +A nil name marks the end of the table. +See +.IR 8l (1) +for details. +The table can be given to the functions below to allow a loaded module +to access those symbols. +.PP +A loaded module is described by a +.B Dynobj +structure: +.IP +.EX +typedef struct { + ulong size; /* total size in bytes */ + ulong text; /* bytes of text */ + ulong data; /* bytes of data */ + ulong bss; /* bytes of bss */ + uchar* base; /* start of text, data, bss */ + int nexport; + Dynsym* export; /* export table */ + int nimport; + Dynsym** import; /* import table */ +} Dynobj; +.EE +.PP +Several fields give sizes of the module's components, as noted in comments above. +.I Base +gives the address at which the module has been loaded. +All its internal +references have been adjusted where needed to reflect its current address. +.I Export +points to a symbol table listing the symbols exported by the module; +.I nexport +gives the table's length. +.I Import +points to a list of symbols imported by the module; +note that each entry actually points to an entry in a symbol table +provided by the program that loaded the module (see below). +.I Nimport +gives the import table's length. +If the import table is not required, call +.I dynfreeimport +on the module pointer to free it. +.PP +.I Dynfindysm +looks up the entry for the given +.I name +in symbol table +.I syms +(of length +.IR nsym ). +It returns a pointer to the entry if found; nil otherwise. +The symbol table must be sorted by name in ascending order. +.PP +.I Dyntabsize +returns the length of symbol table +.IR t , +defined to be the number of +.B Dynsym +values starting at +.I t +that have non-nil +.I name +fields. +It is used to find the length of +.BR _exporttab . +.PP +.I Dynloadfd +loads a module from the file open for reading on +.IR fd , +and returns the resulting module pointer on success, +or nil on error. +If +.I maxsize +is non-zero +the size of the dynamically-loaded module's code and data +is limited to +.I maxsize +bytes. +.I Exports +is an array of +.I nexport +symbols in the current program that can be imported by the current module. +It uses +.IR read (2) +and +.IR seek (2) +to access +.IR fd , +and calls +.I werrstr +(see +.IR errstr (2)) +to set the error string if necessary. +.PP +.I Dynloadgen +is a more general function that can load a module from an +arbitrary source, not just an open file descriptor. +(In particular, it can be +called by the kernel using functions internal to the kernel +instead of making system calls.) +.IR Exports , +.I nexport +and +.I maxsize +are just as for +.IR dynloadfd . +.I File +is a pointer to a structure defined by the caller that represents the file +containing the module. +It is passed to +.I read +and +.IR seek . +.I Read +is invoked as +.BI (*read)( file , buf ,\ \fInbytes\fP)\fR.\fP +.I Read +should read +.I nbytes +of data from +.I file +into +.I buf +and return the number of bytes transferred. +It should return -1 on error. +.I Seek +is invoked as +.BI (*seek)( file , n ,\ \fItype\fP) +where +.I n +and +.I type +are just as for +.IR seek (2); +it should seek to the requested offset in +.IR file , +or return -1 on error. +.I Dynloadgen +returns a pointer to the loaded module on success. +On error, +it returns nil after calling its +.I err +parameter to set the error string. +.PP +.I Dynimport +returns a pointer to the value of the symbol +.I name +in loaded module +.IR o , +or +.I nil +if +.I o +does not export a symbol with the given +.IR name . +If +.I sig +is non-zero, the exported symbol's signature must equal +.IR sig , +or +.I dynimport +again returns nil. +For example: +.IP +.EX +Dev *d; +d = dynimport(obj, "XXXdevtab", signof(*d)); +if(d == nil) + error("not a dynamically-loadable driver"); +.EE +.PP +.I Dynobjfree +frees the module +.IR o . +There is no reference counting: it is the caller's responsibility to decide whether +a module is no longer needed. +.SH SEE ALSO +.IR 8l (1), +.\".IR mach (2), +.IR a.out (6) +.SH DIAGNOSTICS +Functions that return pointers return nil on error. +.I Dynloadfd +sets the error string and returns nil. diff --git a/sys/src/libdynld/NOTICE b/sys/src/libdynld/NOTICE new file mode 100644 index 0000000..fca1655 --- /dev/null +++ b/sys/src/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-2007 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/sys/src/libdynld/dynld-386.c b/sys/src/libdynld/dynld-386.c new file mode 100644 index 0000000..7381675 --- /dev/null +++ b/sys/src/libdynld/dynld-386.c @@ -0,0 +1,43 @@ +#include +#include +#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/sys/src/libdynld/dynld-68000.c b/sys/src/libdynld/dynld-68000.c new file mode 100644 index 0000000..a258106 --- /dev/null +++ b/sys/src/libdynld/dynld-68000.c @@ -0,0 +1,23 @@ +#include +#include +#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/sys/src/libdynld/dynld-amd64.c b/sys/src/libdynld/dynld-amd64.c new file mode 100644 index 0000000..693af64 --- /dev/null +++ b/sys/src/libdynld/dynld-amd64.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index" + +long +dynmagic(void) +{ + return DYN_MAGIC | S_MAGIC; +} + +char* +dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab) +{ + USED(b); + USED(p); + USED(m); + USED(tab); + USED(ntab); + return "amd64 unimplemented"; +} diff --git a/sys/src/libdynld/dynld-arm.c b/sys/src/libdynld/dynld-arm.c new file mode 100644 index 0000000..1e455c9 --- /dev/null +++ b/sys/src/libdynld/dynld-arm.c @@ -0,0 +1,45 @@ +#include +#include +#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/sys/src/libdynld/dynld-arm64.c b/sys/src/libdynld/dynld-arm64.c new file mode 100644 index 0000000..45cf1db --- /dev/null +++ b/sys/src/libdynld/dynld-arm64.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index" + +long +dynmagic(void) +{ + return DYN_MAGIC | R_MAGIC; +} + +char* +dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab) +{ + USED(b); + USED(p); + USED(m); + USED(tab); + USED(ntab); + return "arm64 unimplemented"; +} diff --git a/sys/src/libdynld/dynld-mips.c b/sys/src/libdynld/dynld-mips.c new file mode 100644 index 0000000..b78b019 --- /dev/null +++ b/sys/src/libdynld/dynld-mips.c @@ -0,0 +1,23 @@ +#include +#include +#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/sys/src/libdynld/dynld-mips64.c b/sys/src/libdynld/dynld-mips64.c new file mode 100644 index 0000000..394bd73 --- /dev/null +++ b/sys/src/libdynld/dynld-mips64.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index" + +long +dynmagic(void) +{ + return DYN_MAGIC | M_MAGIC; +} + +char* +dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab) +{ + USED(b); + USED(p); + USED(m); + USED(tab); + USED(ntab); + return "mips64 unimplemented"; +} diff --git a/sys/src/libdynld/dynld-power.c b/sys/src/libdynld/dynld-power.c new file mode 100644 index 0000000..5afe1fa --- /dev/null +++ b/sys/src/libdynld/dynld-power.c @@ -0,0 +1,66 @@ +#include +#include +#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/sys/src/libdynld/dynld-power64.c b/sys/src/libdynld/dynld-power64.c new file mode 100644 index 0000000..e9c149a --- /dev/null +++ b/sys/src/libdynld/dynld-power64.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index" + +long +dynmagic(void) +{ + return DYN_MAGIC | T_MAGIC; +} + +char* +dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab) +{ + USED(b); + USED(p); + USED(m); + USED(tab); + USED(ntab); + return "power64 unimplemented"; +} diff --git a/sys/src/libdynld/dynld-riscv.c b/sys/src/libdynld/dynld-riscv.c new file mode 100644 index 000000000..c2d0c57b9 --- /dev/null +++ b/sys/src/libdynld/dynld-riscv.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index" + +long +dynmagic(void) +{ + return DYN_MAGIC | Z_MAGIC; +} + +char* +dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab) +{ + USED(b); + USED(p); + USED(m); + USED(tab); + USED(ntab); + return "riscv unimplemented"; +} diff --git a/sys/src/libdynld/dynld-riscv64.c b/sys/src/libdynld/dynld-riscv64.c new file mode 100644 index 000000000..895225b91 --- /dev/null +++ b/sys/src/libdynld/dynld-riscv64.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index" + +long +dynmagic(void) +{ + return DYN_MAGIC | Y_MAGIC; +} + +char* +dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab) +{ + USED(b); + USED(p); + USED(m); + USED(tab); + USED(ntab); + return "riscv64 unimplemented"; +} diff --git a/sys/src/libdynld/dynld-sparc.c b/sys/src/libdynld/dynld-sparc.c new file mode 100644 index 0000000..4ab620f --- /dev/null +++ b/sys/src/libdynld/dynld-sparc.c @@ -0,0 +1,21 @@ +#include +#include +#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/sys/src/libdynld/dynld-spim.c b/sys/src/libdynld/dynld-spim.c new file mode 100644 index 0000000..5e9f208 --- /dev/null +++ b/sys/src/libdynld/dynld-spim.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index" + +long +dynmagic(void) +{ + return DYN_MAGIC | P_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-le (spim) unimplemented"; +} diff --git a/sys/src/libdynld/dynld-spim64.c b/sys/src/libdynld/dynld-spim64.c new file mode 100644 index 0000000..10f4654 --- /dev/null +++ b/sys/src/libdynld/dynld-spim64.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index" + +long +dynmagic(void) +{ + return DYN_MAGIC | N_MAGIC; +} + +char* +dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab) +{ + USED(b); + USED(p); + USED(m); + USED(tab); + USED(ntab); + return "mips64-le (spim64) unimplemented"; +} diff --git a/sys/src/libdynld/dynld.c b/sys/src/libdynld/dynld.c new file mode 100644 index 0000000..fdce17e --- /dev/null +++ b/sys/src/libdynld/dynld.c @@ -0,0 +1,259 @@ +#include +#include +#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/sys/src/libdynld/dynloadfd.c b/sys/src/libdynld/dynloadfd.c new file mode 100644 index 0000000..61d50ae --- /dev/null +++ b/sys/src/libdynld/dynloadfd.c @@ -0,0 +1,36 @@ +#include +#include +#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/sys/src/libdynld/mkfile b/sys/src/libdynld/mkfile new file mode 100644 index 0000000..4a7d701 --- /dev/null +++ b/sys/src/libdynld/mkfile @@ -0,0 +1,10 @@ +