File: /usr/src/linux/arch/sparc/boot/btfixupprep.c

1     /* $Id: btfixupprep.c,v 1.6 2001/08/22 15:27:47 davem Exp $
2        Simple utility to prepare vmlinux image for sparc.
3        Resolves all BTFIXUP uses and settings and creates
4        a special .s object to link to the image.
5        
6        Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7        
8        This program is free software; you can redistribute it and/or modify
9        it under the terms of the GNU General Public License as published by
10        the Free Software Foundation; either version 2 of the License, or
11        (at your option) any later version.
12        
13        This program is distributed in the hope that it will be useful,
14        but WITHOUT ANY WARRANTY; without even the implied warranty of
15        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16        GNU General Public License for more details.
17     
18        You should have received a copy of the GNU General Public License
19        along with this program; if not, write to the Free Software
20        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
21        
22     #include <stdio.h>
23     #include <string.h>
24     #include <ctype.h>
25     #include <errno.h>
26     #include <unistd.h>
27     #include <stdlib.h>
28     #include <malloc.h>
29     
30     #define MAXSYMS 1024
31     
32     static char *symtab = "SYMBOL TABLE:";
33     static char *relrec = "RELOCATION RECORDS FOR [";
34     static int rellen;
35     static int symlen;
36     int mode;
37     
38     struct _btfixup;
39     
40     typedef struct _btfixuprel {
41     	char *sect;
42     	unsigned long offset;
43     	struct _btfixup *f;
44     	int frel;
45     	struct _btfixuprel *next;
46     } btfixuprel;
47     
48     typedef struct _btfixup {
49     	int type;
50     	int setinitval;
51     	unsigned int initval;
52     	char *initvalstr;
53     	char *name;
54     	btfixuprel *rel;
55     } btfixup;
56     
57     btfixup array[MAXSYMS];
58     int last = 0;
59     char buffer[1024];
60     unsigned long lastfoffset = -1;
61     unsigned long lastfrelno;
62     btfixup *lastf;
63     
64     void fatal(void) __attribute__((noreturn));
65     void fatal(void)
66     {
67     	fprintf(stderr, "Malformed output from objdump\n%s\n", buffer);
68     	exit(1);
69     }
70     
71     btfixup *find(int type, char *name)
72     {
73     	int i;
74     	for (i = 0; i < last; i++) {
75     		if (array[i].type == type && !strcmp(array[i].name, name))
76     			return array + i;
77     	}
78     	array[last].type = type;
79     	array[last].name = strdup(name);
80     	array[last].setinitval = 0;
81     	if (!array[last].name) fatal();
82     	array[last].rel = NULL;
83     	last++;
84     	if (last >= MAXSYMS) {
85     		fprintf(stderr, "Ugh. Something strange. More than %d different BTFIXUP symbols\n", MAXSYMS);
86     		exit(1);
87     	}
88     	return array + last - 1;
89     }
90     
91     void set_mode (char *buffer)
92     {
93       	for (mode = 0;; mode++)
94     		if (buffer[mode] < '0' || buffer[mode] > '9')
95     			break;
96     	if (mode != 8 && mode != 16)
97     		fatal();
98     }
99     
100     
101     int main(int argc,char **argv)
102     {
103     	char *p, *q;
104     	char *sect;
105     	int i, j, k;
106     	unsigned int initval;
107     	int shift;
108     	btfixup *f;
109     	btfixuprel *r, **rr;
110     	unsigned long offset;
111     	char *initvalstr;
112     
113     	symlen = strlen(symtab);
114     	while (fgets (buffer, 1024, stdin) != NULL)
115     		if (!strncmp (buffer, symtab, symlen))
116     			goto main0;
117     	fatal();
118     main0:
119     	rellen = strlen(relrec);
120     	while (fgets (buffer, 1024, stdin) != NULL)
121     		if (!strncmp (buffer, relrec, rellen))
122     			goto main1;
123     	fatal();
124     main1:
125     	sect = malloc(strlen (buffer + rellen) + 1);
126     	if (!sect) fatal();
127     	strcpy (sect, buffer + rellen);
128     	p = strchr (sect, ']');
129     	if (!p) fatal();
130     	*p = 0;
131     	if (fgets (buffer, 1024, stdin) == NULL)
132     		fatal();
133     	while (fgets (buffer, 1024, stdin) != NULL) {
134     		int nbase;
135     		if (!strncmp (buffer, relrec, rellen))
136     			goto main1;
137     		if (mode == 0)
138     			set_mode (buffer);
139     		p = strchr (buffer, '\n');
140     		if (p) *p = 0;
141     		if (strlen (buffer) < 22+mode)
142     			continue;
143     		if (strncmp (buffer + mode, " R_SPARC_", 9))
144     			continue;
145     		nbase = 27 - 8 + mode;
146     		if (buffer[nbase] != '_' || buffer[nbase+1] != '_' || buffer[nbase+2] != '_')
147     			continue;
148     		switch (buffer[nbase+3]) {
149     			case 'f':	/* CALL */
150     			case 'b':	/* BLACKBOX */
151     			case 's':	/* SIMM13 */
152     			case 'a':	/* HALF */
153     			case 'h':	/* SETHI */
154     			case 'i':	/* INT */
155     				break;
156     			default:
157     				continue;
158     		}
159     		p = strchr (buffer + nbase+5, '+');
160     		if (p) *p = 0;
161     		shift = nbase + 5;
162     		if (buffer[nbase+4] == 's' && buffer[nbase+5] == '_') {
163     			shift = nbase + 6;
164     			if (strcmp (sect, ".text.init")) {
165     				fprintf(stderr, "Wrong use of '%s' BTFIXUPSET.\nBTFIXUPSET_CALL can be used only in __init sections\n", buffer+shift);
166     				exit(1);
167     			}
168     		} else if (buffer[nbase+4] != '_')
169     			continue;
170     		if (strcmp (sect, ".text") && strcmp (sect, ".text.init") && strcmp (sect, ".fixup") && (strcmp (sect, "__ksymtab") || buffer[nbase+3] != 'f')) {
171     			if (buffer[nbase+3] == 'f')
172     				fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .text.init, .fixup and __ksymtab\n", buffer + shift, sect);
173     			else
174     				fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .fixup and .text.init\n", buffer + shift, sect);
175     			exit(1);
176     		}
177     		p = strstr (buffer + shift, "__btset_");
178     		if (p && buffer[nbase+4] == 's') {
179     			fprintf(stderr, "__btset_ in BTFIXUP name can only be used when defining the variable, not for setting\n%s\n", buffer);
180     			exit(1);
181     		}
182     		initval = 0;
183     		initvalstr = NULL;
184     		if (p) {
185     			if (p[8] != '0' || p[9] != 'x') {
186     				fprintf(stderr, "Pre-initialized values can be only initialized with hexadecimal constants starting 0x\n%s\n", buffer);
187     				exit(1);
188     			}
189     			initval = strtoul(p + 10, &q, 16);
190     			if (*q || !initval) {
191     				fprintf(stderr, "Pre-initialized values can be only in the form name__btset_0xXXXXXXXX where X are hex digits.\nThey cannot be name__btset_0x00000000 though. Use BTFIXUPDEF_XX instead of BTFIXUPDEF_XX_INIT then.\n%s\n", buffer);
192     				exit(1);
193     			}
194     			initvalstr = p + 10;
195     			*p = 0;
196     		}
197     		f = find(buffer[nbase+3], buffer + shift);
198     		if (buffer[nbase+4] == 's')
199     			continue;
200     		switch (buffer[nbase+3]) {
201     		case 'f':
202     			if (initval) {
203     				fprintf(stderr, "Cannot use pre-initalized fixups for calls\n%s\n", buffer);
204     				exit(1);
205     			}
206     			if (!strcmp (sect, "__ksymtab")) {
207     				if (strncmp (buffer + mode+9, "32        ", 10)) {
208     					fprintf(stderr, "BTFIXUP_CALL in EXPORT_SYMBOL results in relocation other than R_SPARC_32\n\%s\n", buffer);
209     					exit(1);
210     				}
211     			} else if (strncmp (buffer + mode+9, "WDISP30   ", 10) &&
212     				   strncmp (buffer + mode+9, "HI22      ", 10) &&
213     				   strncmp (buffer + mode+9, "LO10      ", 10)) {
214     				fprintf(stderr, "BTFIXUP_CALL results in relocation other than R_SPARC_WDISP30, R_SPARC_HI22 or R_SPARC_LO10\n%s\n", buffer);
215     				exit(1);
216     			}
217     			break;
218     		case 'b':
219     			if (initval) {
220     				fprintf(stderr, "Cannot use pre-initialized fixups for blackboxes\n%s\n", buffer);
221     				exit(1);
222     			}
223     			if (strncmp (buffer + mode+9, "HI22      ", 10)) {
224     				fprintf(stderr, "BTFIXUP_BLACKBOX results in relocation other than R_SPARC_HI22\n%s\n", buffer);
225     				exit(1);
226     			}
227     			break;
228     		case 's':
229     			if (initval + 0x1000 >= 0x2000) {
230     				fprintf(stderr, "Wrong initializer for SIMM13. Has to be from $fffff000 to $00000fff\n%s\n", buffer);
231     				exit(1);
232     			}
233     			if (strncmp (buffer + mode+9, "13        ", 10)) {
234     				fprintf(stderr, "BTFIXUP_SIMM13 results in relocation other than R_SPARC_13\n%s\n", buffer);
235     				exit(1);
236     			}
237     			break;
238     		case 'a':
239     			if (initval + 0x1000 >= 0x2000 && (initval & 0x3ff)) {
240     				fprintf(stderr, "Wrong initializer for HALF.\n%s\n", buffer);
241     				exit(1);
242     			}
243     			if (strncmp (buffer + mode+9, "13        ", 10)) {
244     				fprintf(stderr, "BTFIXUP_HALF results in relocation other than R_SPARC_13\n%s\n", buffer);
245     				exit(1);
246     			}
247     			break;
248     		case 'h':
249     			if (initval & 0x3ff) {
250     				fprintf(stderr, "Wrong initializer for SETHI. Cannot have set low 10 bits\n%s\n", buffer);
251     				exit(1);
252     			}
253     			if (strncmp (buffer + mode+9, "HI22      ", 10)) {
254     				fprintf(stderr, "BTFIXUP_SETHI results in relocation other than R_SPARC_HI22\n%s\n", buffer);
255     				exit(1);
256     			}
257     			break;
258     		case 'i':
259     			if (initval) {
260     				fprintf(stderr, "Cannot use pre-initalized fixups for INT\n%s\n", buffer);
261     				exit(1);
262     			}
263     			if (strncmp (buffer + mode+9, "HI22      ", 10) && strncmp (buffer + mode+9, "LO10      ", 10)) {
264     				fprintf(stderr, "BTFIXUP_INT results in relocation other than R_SPARC_HI22 and R_SPARC_LO10\n%s\n", buffer);
265     				exit(1);
266     			}
267     			break;
268     		}
269     		if (!f->setinitval) {
270     			f->initval = initval;
271     			if (initvalstr) {
272     				f->initvalstr = strdup(initvalstr);
273     				if (!f->initvalstr) fatal();
274     			}
275     			f->setinitval = 1;
276     		} else if (f->initval != initval) {
277     			fprintf(stderr, "Btfixup %s previously used with initializer %s which doesn't match with current initializer\n%s\n",
278     					f->name, f->initvalstr ? : "0x00000000", buffer);
279     			exit(1);
280     		} else if (initval && strcmp(f->initvalstr, initvalstr)) {
281     			fprintf(stderr, "Btfixup %s previously used with initializer %s which doesn't match with current initializer.\n"
282     					"Initializers have to match literally as well.\n%s\n",
283     					f->name, f->initvalstr, buffer);
284     			exit(1);
285     		}
286     		offset = strtoul(buffer, &q, 16);
287     		if (q != buffer + mode || (!offset && (mode == 8 ? strncmp (buffer, "00000000 ", 9) : strncmp (buffer, "0000000000000000 ", 17)))) {
288     			fprintf(stderr, "Malformed relocation address in\n%s\n", buffer);
289     			exit(1);
290     		}
291     		for (k = 0, r = f->rel, rr = &f->rel; r; rr = &r->next, r = r->next, k++)
292     			if (r->offset == offset && !strcmp(r->sect, sect)) {
293     				fprintf(stderr, "Ugh. One address has two relocation records\n");
294     				exit(1);
295     			}
296     		*rr = malloc(sizeof(btfixuprel));
297     		if (!*rr) fatal();
298     		(*rr)->offset = offset;
299     		(*rr)->f = NULL;
300     		if (buffer[nbase+3] == 'f') {
301     			lastf = f;
302     			lastfoffset = offset;
303     			lastfrelno = k;
304     		} else if (lastfoffset + 4 == offset) {
305     			(*rr)->f = lastf;
306     			(*rr)->frel = lastfrelno;
307     		}
308     		(*rr)->sect = sect;
309     		(*rr)->next = NULL;
310     	}
311     	printf("! Generated by btfixupprep. Do not edit.\n\n");
312     	printf("\t.section\t\".data.init\",#alloc,#write\n\t.align\t4\n\n");
313     	printf("\t.global\t___btfixup_start\n___btfixup_start:\n\n");
314     	for (i = 0; i < last; i++) {
315     		f = array + i;
316     		printf("\t.global\t___%cs_%s\n", f->type, f->name);
317     		if (f->type == 'f')
318     			printf("___%cs_%s:\n\t.word 0x%08x,0,0,", f->type, f->name, f->type << 24);
319     		else
320     			printf("___%cs_%s:\n\t.word 0x%08x,0,", f->type, f->name, f->type << 24);
321     		for (j = 0, r = f->rel; r != NULL; j++, r = r->next);
322     		if (j)
323     			printf("%d\n\t.word\t", j * 2);
324     		else
325     			printf("0\n");
326     		for (r = f->rel, j--; r != NULL; j--, r = r->next) {
327     			if (!strcmp (r->sect, ".text"))
328     				printf ("_stext+0x%08lx", r->offset);
329     			else if (!strcmp (r->sect, ".text.init"))
330     				printf ("__init_begin+0x%08lx", r->offset);
331     			else if (!strcmp (r->sect, "__ksymtab"))
332     				printf ("__start___ksymtab+0x%08lx", r->offset);
333     			else if (!strcmp (r->sect, ".fixup"))
334     				printf ("__start___fixup+0x%08lx", r->offset);
335     			else
336     				fatal();
337     			if (f->type == 'f' || !r->f)
338     				printf (",0");
339     			else
340     				printf (",___fs_%s+0x%08x", r->f->name, (4 + r->frel*2)*4 + 4);
341     			if (j) printf (",");
342     			else printf ("\n");
343     		}
344     		printf("\n");
345     	}
346     	printf("\n\t.global\t___btfixup_end\n___btfixup_end:\n");
347     	printf("\n\n! Define undefined references\n\n");
348     	for (i = 0; i < last; i++) {
349     		f = array + i;
350     		if (f->type == 'f') {
351     			printf("\t.global\t___f_%s\n", f->name);
352     			printf("___f_%s:\n", f->name);
353     		}
354     	}
355     	printf("\tretl\n\t nop\n\n");
356     	for (i = 0; i < last; i++) {
357     		f = array + i;
358     		if (f->type != 'f') {
359     			if (!f->initval) {
360     				printf("\t.global\t___%c_%s\n", f->type, f->name);
361     				printf("___%c_%s = 0\n", f->type, f->name);
362     			} else {
363     				printf("\t.global\t___%c_%s__btset_0x%s\n", f->type, f->name, f->initvalstr);
364     				printf("___%c_%s__btset_0x%s = 0x%08x\n", f->type, f->name, f->initvalstr, f->initval);
365     			}
366     		}
367     	}
368     	printf("\n\n");
369         	exit(0);
370     }
371