1 /* $Id: load.c,v 1.30 2020-11-10 20:49:26 phil Exp $ */
2 
3 /*
4  * load and run external functions for systems using v7/BSD style a.out
5  * -plb 11/9/93
6  *
7  * converted to loadx/os_load client 9/27/2020 -- not compiled
8  */
9 
10 /*
11  * How it works;
12  *
13  * uses ld to create an OMAGIC (impure) a.out file (which need
14  * not load on a page boundary)
15  *
16  * runs ld twice; once to determine overall size, and a second time
17  * after load address known.  This avoids needing to know about
18  * relocation bits which tend to be CPU/port dependant.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif /* HAVE_CONFIG_H defined */
24 
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <a.out.h>
29 
30 #include <stdlib.h>			/* for malloc, getenv */
31 #include <stdio.h>
32 
33 #include "h.h"
34 #include "snotypes.h"
35 #include "path.h"			/* LD_PATH */
36 #include "lib.h"			/* prototypes */
37 #include "str.h"			/* strdup */
38 
39 /* is this right? -- ok for OMAGIC */
40 #undef N_SIZE				/* defined in NetBSD nlist.h */
41 #define N_SIZE(A) ((A).a_text + (A).a_data + (A).a_bss)
42 
43 /* NetBSD compatibility */
44 #ifndef N_GETMAGIC
45 #define N_GETMAGIC(A) ((A).a_magic)
46 #endif /* N_GETMAGIC not defined */
47 
48 #ifndef SYM_PREFIX
49 #define SYM_PREFIX "_"			/* XXX most (all?) a.out systems? */
50 #endif /* SYM_PREFIX not defined */
51 
52 static int
ld(char * output,char * addr,const char * func,char * input)53 ld(char *output, char *addr, const char *func, char *input) {
54     char command[1024];			/* XXX */
55 
56     /*
57      * -N		old, impure excutable (OMAGIC)
58      * -o output	output file
59      * -T addr		text addr (data follows)
60      * -e name		entry point
61      * input		relocatable object file (plus libs)!
62      */
63 
64     /* XXX -A <path of mainbol executable??? */
65     /* XXX -lm -lc ?? */
66 
67     sprintf( command, "%s -N -o %s -T %x -e %s%s %s",
68 	    LD_PATH, output, addr, SYM_PREFIX, func, input );
69 
70     /* XXX use direct execvp of ld? pass argv? */
71     return system(command) == 0;
72 }
73 
74 #define PATHLEN 256			/* XXX use MAXPATHLEN from param.h? */
75 
76 /* "file" may include loader options (libs) after filename!! */
77 void *
os_load_library(const char * file)78 os_load_library(const char *file) {
79     return strdup(file);
80 }
81 
82 void *
os_find_symbol(void * lib,const char * func,void ** stash)83 os_find_symbol(void *lib, const char *func, void **stash) {
84     struct exec a;
85     char *file = lib;			/* strdup'ed above */
86     char temp[PATHLEN];
87     char *data;
88     void *entry;
89     long len;				/* size of code+data */
90     int f;
91 
92     /*
93      * "module" lookup does not pass "stash" pointer.
94      * To implement would need to:
95      * 1. link object file ONCE (on load), return pointer to struct
96      * 2. keep either: executable file, namelist file, or namelist in memory
97      *
98      * All of this only REALLY matters for snobol4 shared library, and
99      * the only a.out "BSD" systems I can think of that used a.out .so
100      * files (SunOS4, FreeBSD, NetBSD) had dlopen.
101      */
102     if (!stash)
103 	return NULL;
104 
105     sprintf( temp, "%s/snoXXXXXX", TMP_DIR);
106     mktemp( temp );			/* exists in v6 */
107 
108     /* link once to get total size! */
109     if (!ld( temp, 0, func, file)) {
110 	goto ld_error;
111     }
112 
113     f = open(temp, O_RDONLY);
114     if (f < 0) {
115 	/* XXX error message? */
116 	goto ld_error;
117     }
118 
119     if (read( f, &a, sizeof(a)) != sizeof(a)) {
120 	/* XXX error message? */
121 	goto header_error;
122     }
123 
124     if (N_GETMAGIC(a) != OMAGIC) {
125 	/* XXX error message? */
126     header_error:
127 	close(f);
128     ld_error:
129 	unlink(temp);
130 	return NULL;			/* fail */
131     }
132     close(f);
133     unlink(temp);
134 
135     len = N_SIZE(a);		      /* total size (code+data+bss) */
136 
137     /* fix here for NMAGIC or ZMAGIC;  use valloc? */
138     data = malloc(len);
139     if (data == NULL) {
140 	return NULL;
141     }
142 
143     /* XXX need only zero bss! */
144     bzero( data, len );
145 
146     /*
147      * could chain all of the following together in one big if stmt,
148      * but it would be a pain to debug!
149      */
150 
151     /* re-link at new addr */
152     if (!ld( temp, data, fp->name, file) || (f = open(temp, 0)) < 0)
153 	goto file_open_error;
154 
155     if (read( f, &a, sizeof(a)) != sizeof(a))
156 	goto data_read_error;
157 
158     if (N_GETMAGIC(a) != OMAGIC || a.a_entry == 0 || N_SIZE(a) > len)
159 	goto data_read_error;
160 
161     if (read(f, data, len) != len) {
162     data_read_error:
163 	close(f);
164     file_open_error:
165 	unlink(temp);
166 	free(data);
167 	return NULL;
168     }
169     close(f);
170 
171     *stash = data;			/* for os_unload_function */
172     return (void *)a.a_entry;
173 }
174 
175 void
os_unload_function(const char * name,void * stash)176 os_unload_function(const char *name, void *stash) {
177     (void) name;
178     if (stash)
179 	free(stash);
180 }
181 
182 void
os_unload_library(void * lib)183 os_unload_library(void *lib) {
184     free(lib);				/* strdup'ed */
185 }
186