scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

  1#include <errno.h>
  2#include <ctype.h>
  3#include <stdarg.h>
  4#include <stdio.h>
  5#include <stdlib.h>
  6#include <string.h>
  7
  8#include <scc/mach.h>
  9#include <scc/scc.h>
 10#include <scc/ar.h>
 11
 12#include "ld.h"
 13
 14enum {
 15	OUTLIB,
 16	INLIB,
 17};
 18
 19int bintype = -1;
 20Obj *objhead;
 21
 22static int
 23is_needed(Obj *obj)
 24{
 25	int i;
 26	Symbol sym;
 27
 28	for (i = 0; getsym(obj, &i, &sym); i++) {
 29		if (hasref(sym.name))
 30			return 1;
 31	}
 32
 33	return 0;
 34}
 35
 36static void
 37newsec(Section *osec, Obj *obj)
 38{
 39	int align;
 40	Section *sec;
 41	unsigned long long base;
 42
 43	sec = lookupsec(osec->name);
 44	if (sec->type == 'U') {
 45		sec->type = osec->type;
 46		sec->base = osec->base;
 47		sec->size = osec->size;
 48		sec->flags = osec->flags;
 49		align = 0;
 50	} else {
 51		if (sec->type != osec->type
 52		|| sec->flags != osec->flags
 53		|| sec->align != osec->align) {
 54			error("incompatible definition of section %s",
 55			      sec->name);
 56			return;
 57		}
 58		align = osec->align;
 59		align -= sec->size & align-1;
 60		grow(sec, align);
 61	}
 62
 63	rebase(obj, osec->index, sec->size);
 64	copy(obj, osec, sec);
 65}
 66
 67static void
 68newsym(Symbol *sym, Obj *obj)
 69{
 70	int id;
 71	Section sec;
 72
 73	if (sym->type == 'U' || islower(sym->type))
 74		return;
 75
 76	sym = define(sym, obj);
 77	id = sym->section;
 78	getsec(obj, &id, &sec);
 79  	sym->value += sec.base;
 80}
 81
 82static void
 83load(FILE *fp, int inlib)
 84{
 85	int t, i;
 86	Obj *obj;
 87	Section sec;
 88	Symbol sym;
 89	static Obj *last;
 90
 91	if ((t = objprobe(fp, NULL)) < 0) {
 92		error("bad format");
 93		return;
 94	}
 95
 96	if (bintype != -1 && bintype != t) {
 97		error("not compatible object file");
 98		return;
 99	}
100	bintype = t;
101
102	if ((obj = newobj(t)) == NULL) {
103		error(strerror(errno));
104		return;
105	}
106
107	if (readobj(obj, fp) < 0) {
108		error(strerror(errno));
109		goto delete;
110	}
111
112	if (inlib && !is_needed(obj))
113		goto delete;
114
115	for (i = 0; getsec(obj, &i, &sec); i++)
116		newsec(&sec, obj);
117
118	for ( i = 0; getsym(obj, &i, &sym); i++)
119		newsym(&sym, obj);
120
121	obj->next = last;
122	last = obj;
123	if (!objhead)
124		objhead = obj;
125
126	return;
127
128 delete:
129	delobj(obj);
130	return;
131}
132
133static void
134scanindex(FILE *fp)
135{
136	int t, added;
137	long n, i, *offs;
138	char **names;
139	Symbol *sym;
140
141	if (getindex(bintype, &n, &names, &offs, fp) < 0) {
142		error("corrupted index");
143		return;
144	}
145
146	for (added = 0; moreundef(); added = 0) {
147		for (i = 0; i < n; i++) {
148			if (!hasref(names[i]))
149				continue;
150
151			if (fseek(fp, offs[i], SEEK_SET) == EOF) {
152				error(strerror(errno));
153				goto clean;
154			}
155
156			load(fp, OUTLIB);
157			added = 1;
158		}
159
160		if (!added)
161			break;
162	}
163clean:
164	for (i = 0; i < n; i++)
165		free(names[i]);
166	free(names);
167	free(offs);
168}
169
170void
171scanlib(FILE *fp)
172{
173	long cur, off;
174	char memb[SARNAM+1];
175
176	if (bintype == -1) {
177		error("an object file is needed before any library");
178		return;
179	}
180
181	cur = ftell(fp);
182	if ((off = armember(fp, memb, NULL)) < 0)
183		goto corrupted;
184
185	if (strcmp(memb, "/") == 0 || strcmp(memb, "__.SYMDEF") == 0) {
186		scanindex(fp);
187		return;
188	}
189
190	fseek(fp, cur, SEEK_SET);
191	for (;;) {
192		cur = ftell(fp);
193		off = armember(fp, memb, NULL);
194		switch (off) {
195		case -1:
196			goto corrupted;
197		case 0:
198			return;
199		default:
200			membname = memb;
201			if (objprobe(fp, NULL) != -1)
202				load(fp, INLIB);
203			membname = NULL;
204			fseek(fp, cur, SEEK_SET);
205			fseek(fp, off, SEEK_CUR);
206			break;
207		}
208	}
209
210corrupted:
211	error(strerror(errno));
212	error("library corrupted");
213}
214
215static FILE *
216openfile(char *name)
217{
218	size_t pathlen, len;
219	FILE *fp;
220	char **bp;
221	char libname[FILENAME_MAX];
222	static char buffer[FILENAME_MAX];
223
224	filename = name;
225	membname = NULL;
226	if (name[0] != '-' || name[1] != 'l') {
227		if ((fp = fopen(name, "rb")) == NULL)
228			error(strerror(errno));
229		return fp;
230	}
231
232	len = strlen(name+2) + 3;
233	if (len > FILENAME_MAX-1) {
234		error("library name too long");
235		return NULL;
236	}
237	strcat(strcpy(buffer, "lib"), name+2);
238
239	filename = buffer;
240	if ((fp = fopen(buffer, "rb")) != NULL)
241		return fp;
242
243	for (bp = libpaths; *bp; ++bp) {
244		pathlen = strlen(*bp);
245		if (pathlen + len > FILENAME_MAX-1)
246			continue;
247		memcpy(libname, *bp, pathlen);
248		memcpy(libname+pathlen+1, buffer, len);
249		buffer[pathlen] = '/';
250
251		if ((fp = fopen(libname, "rb")) != NULL)
252			return fp;
253	}
254
255	error("not found");
256	return NULL;
257}
258
259static void
260process(char *name)
261{
262	int t;
263	FILE *fp;
264
265	if ((fp = openfile(name)) == NULL)
266		return;
267
268	if (archive(fp))
269		scanlib(fp);
270	else
271		load(fp, OUTLIB);
272
273	fclose(fp);
274}
275
276/*
277 * Get the list of object files that are going to be linked
278 */
279void
280pass1(int argc, char *argv[])
281{
282	char **av, *ap;
283
284	for (av = argv+1; *av; ++av) {
285		if (av[0][0] != '-') {
286			process(*av);
287			continue;
288		}
289		for (ap = &av[0][1]; *ap; ++ap) {
290			switch (*ap) {
291			case 'l':
292				process(nextarg(&ap, &av));
293				break;
294			case 'u':
295				lookupsym(nextarg(&ap, &av));
296				break;
297			}
298		}
299	}
300
301	if (moreundef()) {
302		listundef();
303		exit(EXIT_FAILURE);
304	}
305}