Plan 9 from Bell Labs’s /usr/web/sources/contrib/yk/dist/9legacy/applied/libdynld.diff

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


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 <u.h>
+.br
+.B #include <a.out.h>
+.br
+.B #include <dynld.h>
+.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 <u.h>
+#include <libc.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/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 <u.h>
+#include <libc.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/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 <u.h>
+#include <libc.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 | 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 <u.h>
+#include <libc.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/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 <u.h>
+#include <libc.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 | 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 <u.h>
+#include <libc.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/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 <u.h>
+#include <libc.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 | 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 <u.h>
+#include <libc.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/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 <u.h>
+#include <libc.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 | 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 <u.h>
+#include <libc.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 | 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 <u.h>
+#include <libc.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 | 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 <u.h>
+#include <libc.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/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 <u.h>
+#include <libc.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 | 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 <u.h>
+#include <libc.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 | 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	<u.h>
+#include	<libc.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/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 <u.h>
+#include <libc.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/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 @@
+</$objtype/mkfile
+
+LIB=/$objtype/lib/libdynld.a
+
+OFILES=\
+	dynld-$objtype.$O\
+	dynloadfd.$O\
+	dynld.$O\
+
+</sys/src/cmd/mksyslib
diff --git a/sys/src/mkfile b/sys/src/mkfile
index c050ffc..6035022 100644
--- a/sys/src/mkfile
+++ b/sys/src/mkfile
@@ -14,6 +14,7 @@ LIBS=\
 	libcontrol\
 	libdisk\
 	libdraw\
+	libdynld\
 	libflate\
 	libframe\
 	libgeometry\

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].