]>
Commit | Line | Data |
---|---|---|
14c7c974 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights | |
7 | * Reserved. This file contains Original Code and/or Modifications of | |
8 | * Original Code as defined in and that are subject to the Apple Public | |
9 | * Source License Version 1.1 (the "License"). You may not use this file | |
10 | * except in compliance with the License. Please obtain a copy of the | |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the | |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /* outelf.c output routines for the Netwide Assembler to produce | |
25 | * ELF32 (i386 of course) object file format | |
26 | * | |
27 | * The Netwide Assembler is copyright (C) 1996 Simon Tatham and | |
28 | * Julian Hall. All rights reserved. The software is | |
29 | * redistributable under the licence given in the file "Licence" | |
30 | * distributed in the NASM archive. | |
31 | */ | |
32 | ||
33 | #include <stdio.h> | |
34 | #include <stdlib.h> | |
35 | #include <string.h> | |
36 | #include <ctype.h> | |
37 | ||
38 | #include "nasm.h" | |
39 | #include "nasmlib.h" | |
40 | #include "outform.h" | |
41 | ||
42 | #ifdef OF_ELF | |
43 | ||
44 | /* | |
45 | * Relocation types. | |
46 | */ | |
47 | #define R_386_32 1 /* ordinary absolute relocation */ | |
48 | #define R_386_PC32 2 /* PC-relative relocation */ | |
49 | #define R_386_GOT32 3 /* an offset into GOT */ | |
50 | #define R_386_PLT32 4 /* a PC-relative offset into PLT */ | |
51 | #define R_386_GOTOFF 9 /* an offset from GOT base */ | |
52 | #define R_386_GOTPC 10 /* a PC-relative offset _to_ GOT */ | |
53 | ||
54 | struct Reloc { | |
55 | struct Reloc *next; | |
56 | long address; /* relative to _start_ of section */ | |
57 | long symbol; /* ELF symbol info thingy */ | |
58 | int type; /* type of relocation */ | |
59 | }; | |
60 | ||
61 | struct Symbol { | |
62 | long strpos; /* string table position of name */ | |
63 | long section; /* section ID of the symbol */ | |
64 | int type; /* symbol type */ | |
65 | long value; /* address, or COMMON variable align */ | |
66 | long size; /* size of symbol */ | |
67 | long globnum; /* symbol table offset if global */ | |
68 | struct Symbol *next; /* list of globals in each section */ | |
69 | struct Symbol *nextfwd; /* list of unresolved-size symbols */ | |
70 | char *name; /* used temporarily if in above list */ | |
71 | }; | |
72 | ||
73 | #define SHT_PROGBITS 1 | |
74 | #define SHT_NOBITS 8 | |
75 | ||
76 | #define SHF_WRITE 1 | |
77 | #define SHF_ALLOC 2 | |
78 | #define SHF_EXECINSTR 4 | |
79 | ||
80 | struct Section { | |
81 | struct SAA *data; | |
82 | unsigned long len, size, nrelocs; | |
83 | long index; | |
84 | int type; /* SHT_PROGBITS or SHT_NOBITS */ | |
85 | int align; /* alignment: power of two */ | |
86 | unsigned long flags; /* section flags */ | |
87 | char *name; | |
88 | struct SAA *rel; | |
89 | long rellen; | |
90 | struct Reloc *head, **tail; | |
91 | struct Symbol *gsyms; /* global symbols in section */ | |
92 | }; | |
93 | ||
94 | #define SECT_DELTA 32 | |
95 | static struct Section **sects; | |
96 | static int nsects, sectlen; | |
97 | ||
98 | #define SHSTR_DELTA 256 | |
99 | static char *shstrtab; | |
100 | static int shstrtablen, shstrtabsize; | |
101 | ||
102 | static struct SAA *syms; | |
103 | static unsigned long nlocals, nglobs; | |
104 | ||
105 | static long def_seg; | |
106 | ||
107 | static struct RAA *bsym; | |
108 | ||
109 | static struct SAA *strs; | |
110 | static unsigned long strslen; | |
111 | ||
112 | static FILE *elffp; | |
113 | static efunc error; | |
114 | static evalfunc evaluate; | |
115 | ||
116 | static struct Symbol *fwds; | |
117 | ||
118 | static char elf_module[FILENAME_MAX]; | |
119 | ||
120 | extern struct ofmt of_elf; | |
121 | ||
122 | #define SHN_ABS 0xFFF1 | |
123 | #define SHN_COMMON 0xFFF2 | |
124 | #define SHN_UNDEF 0 | |
125 | ||
126 | #define SYM_SECTION 0x04 | |
127 | #define SYM_GLOBAL 0x10 | |
128 | #define SYM_DATA 0x01 | |
129 | #define SYM_FUNCTION 0x02 | |
130 | ||
131 | #define GLOBAL_TEMP_BASE 6 /* bigger than any constant sym id */ | |
132 | ||
133 | #define SEG_ALIGN 16 /* alignment of sections in file */ | |
134 | #define SEG_ALIGN_1 (SEG_ALIGN-1) | |
135 | ||
136 | static const char align_str[SEG_ALIGN] = ""; /* ANSI will pad this with 0s */ | |
137 | ||
138 | #define ELF_MAX_SECTIONS 16 /* really 10, but let's play safe */ | |
139 | static struct ELF_SECTDATA { | |
140 | void *data; | |
141 | long len; | |
142 | int is_saa; | |
143 | } elf_sects[ELF_MAX_SECTIONS]; | |
144 | static int elf_nsect; | |
145 | static long elf_foffs; | |
146 | ||
147 | static void elf_write(void); | |
148 | static void elf_sect_write(struct Section *, unsigned char *, unsigned long); | |
149 | static void elf_section_header (int, int, int, void *, int, long, | |
150 | int, int, int, int); | |
151 | static void elf_write_sections (void); | |
152 | static struct SAA *elf_build_symtab (long *, long *); | |
153 | static struct SAA *elf_build_reltab (long *, struct Reloc *); | |
154 | static void add_sectname (char *, char *); | |
155 | ||
156 | /* | |
157 | * Special section numbers which are used to define ELF special | |
158 | * symbols, which can be used with WRT to provide PIC relocation | |
159 | * types. | |
160 | */ | |
161 | static long elf_gotpc_sect, elf_gotoff_sect; | |
162 | static long elf_got_sect, elf_plt_sect; | |
163 | static long elf_sym_sect; | |
164 | ||
165 | static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { | |
166 | elffp = fp; | |
167 | error = errfunc; | |
168 | evaluate = eval; | |
169 | (void) ldef; /* placate optimisers */ | |
170 | sects = NULL; | |
171 | nsects = sectlen = 0; | |
172 | syms = saa_init((long)sizeof(struct Symbol)); | |
173 | nlocals = nglobs = 0; | |
174 | bsym = raa_init(); | |
175 | strs = saa_init(1L); | |
176 | saa_wbytes (strs, "\0", 1L); | |
177 | saa_wbytes (strs, elf_module, (long)(strlen(elf_module)+1)); | |
178 | strslen = 2+strlen(elf_module); | |
179 | shstrtab = NULL; | |
180 | shstrtablen = shstrtabsize = 0;; | |
181 | add_sectname ("", ""); | |
182 | ||
183 | fwds = NULL; | |
184 | ||
185 | elf_gotpc_sect = seg_alloc(); | |
186 | ldef("..gotpc", elf_gotpc_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); | |
187 | elf_gotoff_sect = seg_alloc(); | |
188 | ldef("..gotoff", elf_gotoff_sect+1, 0L, NULL, FALSE, FALSE,&of_elf,error); | |
189 | elf_got_sect = seg_alloc(); | |
190 | ldef("..got", elf_got_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); | |
191 | elf_plt_sect = seg_alloc(); | |
192 | ldef("..plt", elf_plt_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); | |
193 | elf_sym_sect = seg_alloc(); | |
194 | ldef("..sym", elf_sym_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); | |
195 | ||
196 | def_seg = seg_alloc(); | |
197 | } | |
198 | ||
199 | static void elf_cleanup(void) { | |
200 | struct Reloc *r; | |
201 | int i; | |
202 | ||
203 | elf_write(); | |
204 | fclose (elffp); | |
205 | for (i=0; i<nsects; i++) { | |
206 | if (sects[i]->type != SHT_NOBITS) | |
207 | saa_free (sects[i]->data); | |
208 | if (sects[i]->head) | |
209 | saa_free (sects[i]->rel); | |
210 | while (sects[i]->head) { | |
211 | r = sects[i]->head; | |
212 | sects[i]->head = sects[i]->head->next; | |
213 | nasm_free (r); | |
214 | } | |
215 | } | |
216 | nasm_free (sects); | |
217 | saa_free (syms); | |
218 | raa_free (bsym); | |
219 | saa_free (strs); | |
220 | } | |
221 | ||
222 | static void add_sectname (char *firsthalf, char *secondhalf) { | |
223 | int len = strlen(firsthalf)+strlen(secondhalf); | |
224 | while (shstrtablen + len + 1 > shstrtabsize) | |
225 | shstrtab = nasm_realloc (shstrtab, (shstrtabsize += SHSTR_DELTA)); | |
226 | strcpy (shstrtab+shstrtablen, firsthalf); | |
227 | strcat (shstrtab+shstrtablen, secondhalf); | |
228 | shstrtablen += len+1; | |
229 | } | |
230 | ||
231 | static int elf_make_section (char *name, int type, int flags, int align) { | |
232 | struct Section *s; | |
233 | ||
234 | s = nasm_malloc (sizeof(*s)); | |
235 | ||
236 | if (type != SHT_NOBITS) | |
237 | s->data = saa_init (1L); | |
238 | s->head = NULL; | |
239 | s->tail = &s->head; | |
240 | s->len = s->size = 0; | |
241 | s->nrelocs = 0; | |
242 | if (!strcmp(name, ".text")) | |
243 | s->index = def_seg; | |
244 | else | |
245 | s->index = seg_alloc(); | |
246 | add_sectname ("", name); | |
247 | s->name = nasm_malloc (1+strlen(name)); | |
248 | strcpy (s->name, name); | |
249 | s->type = type; | |
250 | s->flags = flags; | |
251 | s->align = align; | |
252 | s->gsyms = NULL; | |
253 | ||
254 | if (nsects >= sectlen) | |
255 | sects = nasm_realloc (sects, (sectlen += SECT_DELTA)*sizeof(*sects)); | |
256 | sects[nsects++] = s; | |
257 | ||
258 | return nsects-1; | |
259 | } | |
260 | ||
261 | static long elf_section_names (char *name, int pass, int *bits) { | |
262 | char *p; | |
263 | int flags_and, flags_or, type, align, i; | |
264 | ||
265 | /* | |
266 | * Default is 32 bits. | |
267 | */ | |
268 | if (!name) | |
269 | *bits = 32; | |
270 | ||
271 | if (!name) | |
272 | return def_seg; | |
273 | ||
274 | p = name; | |
275 | while (*p && !isspace(*p)) p++; | |
276 | if (*p) *p++ = '\0'; | |
277 | flags_and = flags_or = type = align = 0; | |
278 | ||
279 | while (*p && isspace(*p)) p++; | |
280 | while (*p) { | |
281 | char *q = p; | |
282 | while (*p && !isspace(*p)) p++; | |
283 | if (*p) *p++ = '\0'; | |
284 | while (*p && isspace(*p)) p++; | |
285 | ||
286 | if (!nasm_strnicmp(q, "align=", 6)) { | |
287 | align = atoi(q+6); | |
288 | if (align == 0) | |
289 | align = 1; | |
290 | if ( (align-1) & align ) { /* means it's not a power of two */ | |
291 | error (ERR_NONFATAL, "section alignment %d is not" | |
292 | " a power of two", align); | |
293 | align = 1; | |
294 | } | |
295 | } else if (!nasm_stricmp(q, "alloc")) { | |
296 | flags_and |= SHF_ALLOC; | |
297 | flags_or |= SHF_ALLOC; | |
298 | } else if (!nasm_stricmp(q, "noalloc")) { | |
299 | flags_and |= SHF_ALLOC; | |
300 | flags_or &= ~SHF_ALLOC; | |
301 | } else if (!nasm_stricmp(q, "exec")) { | |
302 | flags_and |= SHF_EXECINSTR; | |
303 | flags_or |= SHF_EXECINSTR; | |
304 | } else if (!nasm_stricmp(q, "noexec")) { | |
305 | flags_and |= SHF_EXECINSTR; | |
306 | flags_or &= ~SHF_EXECINSTR; | |
307 | } else if (!nasm_stricmp(q, "write")) { | |
308 | flags_and |= SHF_WRITE; | |
309 | flags_or |= SHF_WRITE; | |
310 | } else if (!nasm_stricmp(q, "nowrite")) { | |
311 | flags_and |= SHF_WRITE; | |
312 | flags_or &= ~SHF_WRITE; | |
313 | } else if (!nasm_stricmp(q, "progbits")) { | |
314 | type = SHT_PROGBITS; | |
315 | } else if (!nasm_stricmp(q, "nobits")) { | |
316 | type = SHT_NOBITS; | |
317 | } | |
318 | } | |
319 | ||
320 | if (!strcmp(name, ".comment") || | |
321 | !strcmp(name, ".shstrtab") || | |
322 | !strcmp(name, ".symtab") || | |
323 | !strcmp(name, ".strtab")) { | |
324 | error (ERR_NONFATAL, "attempt to redefine reserved section" | |
325 | "name `%s'", name); | |
326 | return NO_SEG; | |
327 | } | |
328 | ||
329 | for (i=0; i<nsects; i++) | |
330 | if (!strcmp(name, sects[i]->name)) | |
331 | break; | |
332 | if (i == nsects) { | |
333 | if (!strcmp(name, ".text")) | |
334 | i = elf_make_section (name, SHT_PROGBITS, | |
335 | SHF_ALLOC | SHF_EXECINSTR, 16); | |
336 | else if (!strcmp(name, ".data")) | |
337 | i = elf_make_section (name, SHT_PROGBITS, | |
338 | SHF_ALLOC | SHF_WRITE, 4); | |
339 | else if (!strcmp(name, ".bss")) | |
340 | i = elf_make_section (name, SHT_NOBITS, | |
341 | SHF_ALLOC | SHF_WRITE, 4); | |
342 | else | |
343 | i = elf_make_section (name, SHT_PROGBITS, SHF_ALLOC, 1); | |
344 | if (type) | |
345 | sects[i]->type = type; | |
346 | if (align) | |
347 | sects[i]->align = align; | |
348 | sects[i]->flags &= ~flags_and; | |
349 | sects[i]->flags |= flags_or; | |
350 | } else if (pass == 1) { | |
351 | if (type || align || flags_and) | |
352 | error (ERR_WARNING, "section attributes ignored on" | |
353 | " redeclaration of section `%s'", name); | |
354 | } | |
355 | ||
356 | return sects[i]->index; | |
357 | } | |
358 | ||
359 | static void elf_deflabel (char *name, long segment, long offset, | |
360 | int is_global, char *special) { | |
361 | int pos = strslen; | |
362 | struct Symbol *sym; | |
363 | int special_used = FALSE; | |
364 | ||
365 | if (name[0] == '.' && name[1] == '.' && name[2] != '@') { | |
366 | /* | |
367 | * This is a NASM special symbol. We never allow it into | |
368 | * the ELF symbol table, even if it's a valid one. If it | |
369 | * _isn't_ a valid one, we should barf immediately. | |
370 | */ | |
371 | if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") && | |
372 | strcmp(name, "..got") && strcmp(name, "..plt") && | |
373 | strcmp(name, "..sym")) | |
374 | error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); | |
375 | return; | |
376 | } | |
377 | ||
378 | if (is_global == 3) { | |
379 | struct Symbol **s; | |
380 | /* | |
381 | * Fix up a forward-reference symbol size from the first | |
382 | * pass. | |
383 | */ | |
384 | for (s = &fwds; *s; s = &(*s)->nextfwd) | |
385 | if (!strcmp((*s)->name, name)) { | |
386 | struct tokenval tokval; | |
387 | expr *e; | |
388 | char *p = special; | |
389 | ||
390 | while (*p && !isspace(*p)) p++; | |
391 | while (*p && isspace(*p)) p++; | |
392 | stdscan_reset(); | |
393 | stdscan_bufptr = p; | |
394 | tokval.t_type = TOKEN_INVALID; | |
395 | e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); | |
396 | if (e) { | |
397 | if (!is_simple(e)) | |
398 | error (ERR_NONFATAL, "cannot use relocatable" | |
399 | " expression as symbol size"); | |
400 | else | |
401 | (*s)->size = reloc_value(e); | |
402 | } | |
403 | ||
404 | /* | |
405 | * Remove it from the list of unresolved sizes. | |
406 | */ | |
407 | nasm_free ((*s)->name); | |
408 | *s = (*s)->nextfwd; | |
409 | return; | |
410 | } | |
411 | return; /* it wasn't an important one */ | |
412 | } | |
413 | ||
414 | saa_wbytes (strs, name, (long)(1+strlen(name))); | |
415 | strslen += 1+strlen(name); | |
416 | ||
417 | sym = saa_wstruct (syms); | |
418 | ||
419 | sym->strpos = pos; | |
420 | sym->type = is_global ? SYM_GLOBAL : 0; | |
421 | sym->size = 0; | |
422 | if (segment == NO_SEG) | |
423 | sym->section = SHN_ABS; | |
424 | else { | |
425 | int i; | |
426 | sym->section = SHN_UNDEF; | |
427 | if (nsects == 0 && segment == def_seg) { | |
428 | int tempint; | |
429 | if (segment != elf_section_names (".text", 2, &tempint)) | |
430 | error (ERR_PANIC, "strange segment conditions in ELF driver"); | |
431 | sym->section = nsects; | |
432 | } else { | |
433 | for (i=0; i<nsects; i++) | |
434 | if (segment == sects[i]->index) { | |
435 | sym->section = i+1; | |
436 | break; | |
437 | } | |
438 | } | |
439 | } | |
440 | ||
441 | if (is_global == 2) { | |
442 | sym->size = offset; | |
443 | sym->value = 0; | |
444 | sym->section = SHN_COMMON; | |
445 | /* | |
446 | * We have a common variable. Check the special text to see | |
447 | * if it's a valid number and power of two; if so, store it | |
448 | * as the alignment for the common variable. | |
449 | */ | |
450 | if (special) { | |
451 | int err; | |
452 | sym->value = readnum (special, &err); | |
453 | if (err) | |
454 | error(ERR_NONFATAL, "alignment constraint `%s' is not a" | |
455 | " valid number", special); | |
456 | else if ( (sym->value | (sym->value-1)) != 2*sym->value - 1) | |
457 | error(ERR_NONFATAL, "alignment constraint `%s' is not a" | |
458 | " power of two", special); | |
459 | } | |
460 | special_used = TRUE; | |
461 | } else | |
462 | sym->value = (sym->section == SHN_UNDEF ? 0 : offset); | |
463 | ||
464 | if (sym->type == SYM_GLOBAL) { | |
465 | if (sym->section == SHN_UNDEF || sym->section == SHN_COMMON) | |
466 | bsym = raa_write (bsym, segment, nglobs); | |
467 | else { | |
468 | /* | |
469 | * This is a global symbol; so we must add it to the linked | |
470 | * list of global symbols in its section. We'll push it on | |
471 | * the beginning of the list, because it doesn't matter | |
472 | * much which end we put it on and it's easier like this. | |
473 | * | |
474 | * In addition, we check the special text for symbol | |
475 | * type and size information. | |
476 | */ | |
477 | sym->next = sects[sym->section-1]->gsyms; | |
478 | sects[sym->section-1]->gsyms = sym; | |
479 | ||
480 | if (special) { | |
481 | int n = strcspn(special, " "); | |
482 | ||
483 | if (!nasm_strnicmp(special, "function", n)) | |
484 | sym->type |= SYM_FUNCTION; | |
485 | else if (!nasm_strnicmp(special, "data", n) || | |
486 | !nasm_strnicmp(special, "object", n)) | |
487 | sym->type |= SYM_DATA; | |
488 | else | |
489 | error(ERR_NONFATAL, "unrecognised symbol type `%.*s'", | |
490 | n, special); | |
491 | if (special[n]) { | |
492 | struct tokenval tokval; | |
493 | expr *e; | |
494 | int fwd = FALSE; | |
495 | ||
496 | while (special[n] && isspace(special[n])) | |
497 | n++; | |
498 | /* | |
499 | * We have a size expression; attempt to | |
500 | * evaluate it. | |
501 | */ | |
502 | stdscan_reset(); | |
503 | stdscan_bufptr = special+n; | |
504 | tokval.t_type = TOKEN_INVALID; | |
505 | e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error, NULL); | |
506 | if (fwd) { | |
507 | sym->nextfwd = fwds; | |
508 | fwds = sym; | |
509 | sym->name = nasm_strdup(name); | |
510 | } else if (e) { | |
511 | if (!is_simple(e)) | |
512 | error (ERR_NONFATAL, "cannot use relocatable" | |
513 | " expression as symbol size"); | |
514 | else | |
515 | sym->size = reloc_value(e); | |
516 | } | |
517 | } | |
518 | special_used = TRUE; | |
519 | } | |
520 | } | |
521 | sym->globnum = nglobs; | |
522 | nglobs++; | |
523 | } else | |
524 | nlocals++; | |
525 | ||
526 | if (special && !special_used) | |
527 | error(ERR_NONFATAL, "no special symbol features supported here"); | |
528 | } | |
529 | ||
530 | static void elf_add_reloc (struct Section *sect, long segment, | |
531 | int type) { | |
532 | struct Reloc *r; | |
533 | ||
534 | r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); | |
535 | sect->tail = &r->next; | |
536 | r->next = NULL; | |
537 | ||
538 | r->address = sect->len; | |
539 | if (segment == NO_SEG) | |
540 | r->symbol = 2; | |
541 | else { | |
542 | int i; | |
543 | r->symbol = 0; | |
544 | for (i=0; i<nsects; i++) | |
545 | if (segment == sects[i]->index) | |
546 | r->symbol = i+3; | |
547 | if (!r->symbol) | |
548 | r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment); | |
549 | } | |
550 | r->type = type; | |
551 | ||
552 | sect->nrelocs++; | |
553 | } | |
554 | ||
555 | /* | |
556 | * This routine deals with ..got and ..sym relocations: the more | |
557 | * complicated kinds. In shared-library writing, some relocations | |
558 | * with respect to global symbols must refer to the precise symbol | |
559 | * rather than referring to an offset from the base of the section | |
560 | * _containing_ the symbol. Such relocations call to this routine, | |
561 | * which searches the symbol list for the symbol in question. | |
562 | * | |
563 | * R_386_GOT32 references require the _exact_ symbol address to be | |
564 | * used; R_386_32 references can be at an offset from the symbol. | |
565 | * The boolean argument `exact' tells us this. | |
566 | * | |
567 | * Return value is the adjusted value of `addr', having become an | |
568 | * offset from the symbol rather than the section. Should always be | |
569 | * zero when returning from an exact call. | |
570 | * | |
571 | * Limitation: if you define two symbols at the same place, | |
572 | * confusion will occur. | |
573 | * | |
574 | * Inefficiency: we search, currently, using a linked list which | |
575 | * isn't even necessarily sorted. | |
576 | */ | |
577 | static long elf_add_gsym_reloc (struct Section *sect, | |
578 | long segment, long offset, | |
579 | int type, int exact) { | |
580 | struct Reloc *r; | |
581 | struct Section *s; | |
582 | struct Symbol *sym, *sm; | |
583 | int i; | |
584 | ||
585 | /* | |
586 | * First look up the segment/offset pair and find a global | |
587 | * symbol corresponding to it. If it's not one of our segments, | |
588 | * then it must be an external symbol, in which case we're fine | |
589 | * doing a normal elf_add_reloc after first sanity-checking | |
590 | * that the offset from the symbol is zero. | |
591 | */ | |
592 | s = NULL; | |
593 | for (i=0; i<nsects; i++) | |
594 | if (segment == sects[i]->index) { | |
595 | s = sects[i]; | |
596 | break; | |
597 | } | |
598 | if (!s) { | |
599 | if (exact && offset != 0) | |
600 | error (ERR_NONFATAL, "unable to find a suitable global symbol" | |
601 | " for this reference"); | |
602 | else | |
603 | elf_add_reloc (sect, segment, type); | |
604 | return offset; | |
605 | } | |
606 | ||
607 | if (exact) { | |
608 | /* | |
609 | * Find a symbol pointing _exactly_ at this one. | |
610 | */ | |
611 | for (sym = s->gsyms; sym; sym = sym->next) | |
612 | if (sym->value == offset) | |
613 | break; | |
614 | } else { | |
615 | /* | |
616 | * Find the nearest symbol below this one. | |
617 | */ | |
618 | sym = NULL; | |
619 | for (sm = s->gsyms; sm; sm = sm->next) | |
620 | if (sm->value <= offset && (!sym || sm->value > sym->value)) | |
621 | sym = sm; | |
622 | } | |
623 | if (!sym && exact) { | |
624 | error (ERR_NONFATAL, "unable to find a suitable global symbol" | |
625 | " for this reference"); | |
626 | return 0; | |
627 | } | |
628 | ||
629 | r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); | |
630 | sect->tail = &r->next; | |
631 | r->next = NULL; | |
632 | ||
633 | r->address = sect->len; | |
634 | r->symbol = GLOBAL_TEMP_BASE + sym->globnum; | |
635 | r->type = type; | |
636 | ||
637 | sect->nrelocs++; | |
638 | ||
639 | return offset - sym->value; | |
640 | } | |
641 | ||
642 | static void elf_out (long segto, void *data, unsigned long type, | |
643 | long segment, long wrt) { | |
644 | struct Section *s; | |
645 | long realbytes = type & OUT_SIZMASK; | |
646 | long addr; | |
647 | unsigned char mydata[4], *p; | |
648 | int i; | |
649 | ||
650 | type &= OUT_TYPMASK; | |
651 | ||
652 | /* | |
653 | * handle absolute-assembly (structure definitions) | |
654 | */ | |
655 | if (segto == NO_SEG) { | |
656 | if (type != OUT_RESERVE) | |
657 | error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" | |
658 | " space"); | |
659 | return; | |
660 | } | |
661 | ||
662 | s = NULL; | |
663 | for (i=0; i<nsects; i++) | |
664 | if (segto == sects[i]->index) { | |
665 | s = sects[i]; | |
666 | break; | |
667 | } | |
668 | if (!s) { | |
669 | int tempint; /* ignored */ | |
670 | if (segto != elf_section_names (".text", 2, &tempint)) | |
671 | error (ERR_PANIC, "strange segment conditions in ELF driver"); | |
672 | else | |
673 | s = sects[nsects-1]; | |
674 | } | |
675 | ||
676 | if (s->type == SHT_NOBITS && type != OUT_RESERVE) { | |
677 | error(ERR_WARNING, "attempt to initialise memory in" | |
678 | " BSS section `%s': ignored", s->name); | |
679 | if (type == OUT_REL2ADR) | |
680 | realbytes = 2; | |
681 | else if (type == OUT_REL4ADR) | |
682 | realbytes = 4; | |
683 | s->len += realbytes; | |
684 | return; | |
685 | } | |
686 | ||
687 | if (type == OUT_RESERVE) { | |
688 | if (s->type == SHT_PROGBITS) { | |
689 | error(ERR_WARNING, "uninitialised space declared in" | |
690 | " non-BSS section `%s': zeroing", s->name); | |
691 | elf_sect_write (s, NULL, realbytes); | |
692 | } else | |
693 | s->len += realbytes; | |
694 | } else if (type == OUT_RAWDATA) { | |
695 | if (segment != NO_SEG) | |
696 | error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); | |
697 | elf_sect_write (s, data, realbytes); | |
698 | } else if (type == OUT_ADDRESS) { | |
699 | addr = *(long *)data; | |
700 | if (segment != NO_SEG) { | |
701 | if (segment % 2) { | |
702 | error(ERR_NONFATAL, "ELF format does not support" | |
703 | " segment base references"); | |
704 | } else { | |
705 | if (wrt == NO_SEG) { | |
706 | elf_add_reloc (s, segment, R_386_32); | |
707 | } else if (wrt == elf_gotpc_sect+1) { | |
708 | /* | |
709 | * The user will supply GOT relative to $$. ELF | |
710 | * will let us have GOT relative to $. So we | |
711 | * need to fix up the data item by $-$$. | |
712 | */ | |
713 | addr += s->len; | |
714 | elf_add_reloc (s, segment, R_386_GOTPC); | |
715 | } else if (wrt == elf_gotoff_sect+1) { | |
716 | elf_add_reloc (s, segment, R_386_GOTOFF); | |
717 | } else if (wrt == elf_got_sect+1) { | |
718 | addr = elf_add_gsym_reloc (s, segment, addr, | |
719 | R_386_GOT32, TRUE); | |
720 | } else if (wrt == elf_sym_sect+1) { | |
721 | addr = elf_add_gsym_reloc (s, segment, addr, | |
722 | R_386_32, FALSE); | |
723 | } else if (wrt == elf_plt_sect+1) { | |
724 | error(ERR_NONFATAL, "ELF format cannot produce non-PC-" | |
725 | "relative PLT references"); | |
726 | } else { | |
727 | error (ERR_NONFATAL, "ELF format does not support this" | |
728 | " use of WRT"); | |
729 | wrt = NO_SEG; /* we can at least _try_ to continue */ | |
730 | } | |
731 | } | |
732 | } | |
733 | p = mydata; | |
734 | if (realbytes != 4 && segment != NO_SEG) | |
735 | error (ERR_NONFATAL, "ELF format does not support non-32-bit" | |
736 | " relocations"); | |
737 | WRITELONG (p, addr); | |
738 | elf_sect_write (s, mydata, realbytes); | |
739 | } else if (type == OUT_REL2ADR) { | |
740 | error (ERR_NONFATAL, "ELF format does not support 16-bit" | |
741 | " relocations"); | |
742 | } else if (type == OUT_REL4ADR) { | |
743 | if (segment == segto) | |
744 | error(ERR_PANIC, "intra-segment OUT_REL4ADR"); | |
745 | if (segment != NO_SEG && segment % 2) { | |
746 | error(ERR_NONFATAL, "ELF format does not support" | |
747 | " segment base references"); | |
748 | } else { | |
749 | if (wrt == NO_SEG) { | |
750 | elf_add_reloc (s, segment, R_386_PC32); | |
751 | } else if (wrt == elf_plt_sect+1) { | |
752 | elf_add_reloc (s, segment, R_386_PLT32); | |
753 | } else if (wrt == elf_gotpc_sect+1 || | |
754 | wrt == elf_gotoff_sect+1 || | |
755 | wrt == elf_got_sect+1) { | |
756 | error(ERR_NONFATAL, "ELF format cannot produce PC-" | |
757 | "relative GOT references"); | |
758 | } else { | |
759 | error (ERR_NONFATAL, "ELF format does not support this" | |
760 | " use of WRT"); | |
761 | wrt = NO_SEG; /* we can at least _try_ to continue */ | |
762 | } | |
763 | } | |
764 | p = mydata; | |
765 | WRITELONG (p, *(long*)data - realbytes); | |
766 | elf_sect_write (s, mydata, 4L); | |
767 | } | |
768 | } | |
769 | ||
770 | static void elf_write(void) { | |
771 | int nsections, align; | |
772 | char *p; | |
773 | int commlen; | |
774 | char comment[64]; | |
775 | int i; | |
776 | ||
777 | struct SAA *symtab; | |
778 | long symtablen, symtablocal; | |
779 | ||
780 | /* | |
781 | * Work out how many sections we will have. We have SHN_UNDEF, | |
782 | * then the flexible user sections, then the four fixed | |
783 | * sections `.comment', `.shstrtab', `.symtab' and `.strtab', | |
784 | * then optionally relocation sections for the user sections. | |
785 | */ | |
786 | nsections = 5; /* SHN_UNDEF and the fixed ones */ | |
787 | add_sectname ("", ".comment"); | |
788 | add_sectname ("", ".shstrtab"); | |
789 | add_sectname ("", ".symtab"); | |
790 | add_sectname ("", ".strtab"); | |
791 | for (i=0; i<nsects; i++) { | |
792 | nsections++; /* for the section itself */ | |
793 | if (sects[i]->head) { | |
794 | nsections++; /* for its relocations */ | |
795 | add_sectname (".rel", sects[i]->name); | |
796 | } | |
797 | } | |
798 | ||
799 | /* | |
800 | * Do the comment. | |
801 | */ | |
802 | *comment = '\0'; | |
803 | commlen = 2+sprintf(comment+1, "The Netwide Assembler %s", NASM_VER); | |
804 | ||
805 | /* | |
806 | * Output the ELF header. | |
807 | */ | |
808 | fwrite ("\177ELF\1\1\1\0\0\0\0\0\0\0\0\0", 16, 1, elffp); | |
809 | fwriteshort (1, elffp); /* ET_REL relocatable file */ | |
810 | fwriteshort (3, elffp); /* EM_386 processor ID */ | |
811 | fwritelong (1L, elffp); /* EV_CURRENT file format version */ | |
812 | fwritelong (0L, elffp); /* no entry point */ | |
813 | fwritelong (0L, elffp); /* no program header table */ | |
814 | fwritelong (0x40L, elffp); /* section headers straight after | |
815 | * ELF header plus alignment */ | |
816 | fwritelong (0L, elffp); /* 386 defines no special flags */ | |
817 | fwriteshort (0x34, elffp); /* size of ELF header */ | |
818 | fwriteshort (0, elffp); /* no program header table, again */ | |
819 | fwriteshort (0, elffp); /* still no program header table */ | |
820 | fwriteshort (0x28, elffp); /* size of section header */ | |
821 | fwriteshort (nsections, elffp); /* number of sections */ | |
822 | fwriteshort (nsects+2, elffp); /* string table section index for | |
823 | * section header table */ | |
824 | fwritelong (0L, elffp); /* align to 0x40 bytes */ | |
825 | fwritelong (0L, elffp); | |
826 | fwritelong (0L, elffp); | |
827 | ||
828 | /* | |
829 | * Build the symbol table and relocation tables. | |
830 | */ | |
831 | symtab = elf_build_symtab (&symtablen, &symtablocal); | |
832 | for (i=0; i<nsects; i++) | |
833 | if (sects[i]->head) | |
834 | sects[i]->rel = elf_build_reltab (§s[i]->rellen, | |
835 | sects[i]->head); | |
836 | ||
837 | /* | |
838 | * Now output the section header table. | |
839 | */ | |
840 | ||
841 | elf_foffs = 0x40 + 0x28 * nsections; | |
842 | align = ((elf_foffs+SEG_ALIGN_1) & ~SEG_ALIGN_1) - elf_foffs; | |
843 | elf_foffs += align; | |
844 | elf_nsect = 0; | |
845 | ||
846 | elf_section_header (0, 0, 0, NULL, FALSE, 0L, 0, 0, 0, 0); /* SHN_UNDEF */ | |
847 | p = shstrtab+1; | |
848 | for (i=0; i<nsects; i++) { | |
849 | elf_section_header (p - shstrtab, sects[i]->type, sects[i]->flags, | |
850 | (sects[i]->type == SHT_PROGBITS ? | |
851 | sects[i]->data : NULL), TRUE, | |
852 | sects[i]->len, 0, 0, sects[i]->align, 0); | |
853 | p += strlen(p)+1; | |
854 | } | |
855 | elf_section_header (p - shstrtab, 1, 0, comment, FALSE, | |
856 | (long)commlen, 0, 0, 1, 0);/* .comment */ | |
857 | p += strlen(p)+1; | |
858 | elf_section_header (p - shstrtab, 3, 0, shstrtab, FALSE, | |
859 | (long)shstrtablen, 0, 0, 1, 0);/* .shstrtab */ | |
860 | p += strlen(p)+1; | |
861 | elf_section_header (p - shstrtab, 2, 0, symtab, TRUE, | |
862 | symtablen, nsects+4, symtablocal, 4, 16);/* .symtab */ | |
863 | p += strlen(p)+1; | |
864 | elf_section_header (p - shstrtab, 3, 0, strs, TRUE, | |
865 | strslen, 0, 0, 1, 0); /* .strtab */ | |
866 | for (i=0; i<nsects; i++) if (sects[i]->head) { | |
867 | p += strlen(p)+1; | |
868 | elf_section_header (p - shstrtab, 9, 0, sects[i]->rel, TRUE, | |
869 | sects[i]->rellen, nsects+3, i+1, 4, 8); | |
870 | } | |
871 | ||
872 | fwrite (align_str, align, 1, elffp); | |
873 | ||
874 | /* | |
875 | * Now output the sections. | |
876 | */ | |
877 | elf_write_sections(); | |
878 | ||
879 | saa_free (symtab); | |
880 | } | |
881 | ||
882 | static struct SAA *elf_build_symtab (long *len, long *local) { | |
883 | struct SAA *s = saa_init(1L); | |
884 | struct Symbol *sym; | |
885 | unsigned char entry[16], *p; | |
886 | int i; | |
887 | ||
888 | *len = *local = 0; | |
889 | ||
890 | /* | |
891 | * First, an all-zeros entry, required by the ELF spec. | |
892 | */ | |
893 | saa_wbytes (s, NULL, 16L); /* null symbol table entry */ | |
894 | *len += 16; | |
895 | (*local)++; | |
896 | ||
897 | /* | |
898 | * Next, an entry for the file name. | |
899 | */ | |
900 | p = entry; | |
901 | WRITELONG (p, 1); /* we know it's 1st thing in strtab */ | |
902 | WRITELONG (p, 0); /* no value */ | |
903 | WRITELONG (p, 0); /* no size either */ | |
904 | WRITESHORT (p, 4); /* type FILE */ | |
905 | WRITESHORT (p, SHN_ABS); | |
906 | saa_wbytes (s, entry, 16L); | |
907 | *len += 16; | |
908 | (*local)++; | |
909 | ||
910 | /* | |
911 | * Now some standard symbols defining the segments, for relocation | |
912 | * purposes. | |
913 | */ | |
914 | for (i = 1; i <= nsects+1; i++) { | |
915 | p = entry; | |
916 | WRITELONG (p, 0); /* no symbol name */ | |
917 | WRITELONG (p, 0); /* offset zero */ | |
918 | WRITELONG (p, 0); /* size zero */ | |
919 | WRITESHORT (p, 3); /* local section-type thing */ | |
920 | WRITESHORT (p, (i==1 ? SHN_ABS : i-1)); /* the section id */ | |
921 | saa_wbytes (s, entry, 16L); | |
922 | *len += 16; | |
923 | (*local)++; | |
924 | } | |
925 | ||
926 | /* | |
927 | * Now the other local symbols. | |
928 | */ | |
929 | saa_rewind (syms); | |
930 | while ( (sym = saa_rstruct (syms)) ) { | |
931 | if (sym->type & SYM_GLOBAL) | |
932 | continue; | |
933 | p = entry; | |
934 | WRITELONG (p, sym->strpos); | |
935 | WRITELONG (p, sym->value); | |
936 | WRITELONG (p, sym->size); | |
937 | WRITESHORT (p, sym->type); /* local non-typed thing */ | |
938 | WRITESHORT (p, sym->section); | |
939 | saa_wbytes (s, entry, 16L); | |
940 | *len += 16; | |
941 | (*local)++; | |
942 | } | |
943 | ||
944 | /* | |
945 | * Now the global symbols. | |
946 | */ | |
947 | saa_rewind (syms); | |
948 | while ( (sym = saa_rstruct (syms)) ) { | |
949 | if (!(sym->type & SYM_GLOBAL)) | |
950 | continue; | |
951 | p = entry; | |
952 | WRITELONG (p, sym->strpos); | |
953 | WRITELONG (p, sym->value); | |
954 | WRITELONG (p, sym->size); | |
955 | WRITESHORT (p, sym->type); /* global non-typed thing */ | |
956 | WRITESHORT (p, sym->section); | |
957 | saa_wbytes (s, entry, 16L); | |
958 | *len += 16; | |
959 | } | |
960 | ||
961 | return s; | |
962 | } | |
963 | ||
964 | static struct SAA *elf_build_reltab (long *len, struct Reloc *r) { | |
965 | struct SAA *s; | |
966 | unsigned char *p, entry[8]; | |
967 | ||
968 | if (!r) | |
969 | return NULL; | |
970 | ||
971 | s = saa_init(1L); | |
972 | *len = 0; | |
973 | ||
974 | while (r) { | |
975 | long sym = r->symbol; | |
976 | ||
977 | if (sym >= GLOBAL_TEMP_BASE) | |
978 | sym += -GLOBAL_TEMP_BASE + (nsects+3) + nlocals; | |
979 | ||
980 | p = entry; | |
981 | WRITELONG (p, r->address); | |
982 | WRITELONG (p, (sym << 8) + r->type); | |
983 | saa_wbytes (s, entry, 8L); | |
984 | *len += 8; | |
985 | ||
986 | r = r->next; | |
987 | } | |
988 | ||
989 | return s; | |
990 | } | |
991 | ||
992 | static void elf_section_header (int name, int type, int flags, | |
993 | void *data, int is_saa, long datalen, | |
994 | int link, int info, int align, int eltsize) { | |
995 | elf_sects[elf_nsect].data = data; | |
996 | elf_sects[elf_nsect].len = datalen; | |
997 | elf_sects[elf_nsect].is_saa = is_saa; | |
998 | elf_nsect++; | |
999 | ||
1000 | fwritelong ((long)name, elffp); | |
1001 | fwritelong ((long)type, elffp); | |
1002 | fwritelong ((long)flags, elffp); | |
1003 | fwritelong (0L, elffp); /* no address, ever, in object files */ | |
1004 | fwritelong (type == 0 ? 0L : elf_foffs, elffp); | |
1005 | fwritelong (datalen, elffp); | |
1006 | if (data) | |
1007 | elf_foffs += (datalen+SEG_ALIGN_1) & ~SEG_ALIGN_1; | |
1008 | fwritelong ((long)link, elffp); | |
1009 | fwritelong ((long)info, elffp); | |
1010 | fwritelong ((long)align, elffp); | |
1011 | fwritelong ((long)eltsize, elffp); | |
1012 | } | |
1013 | ||
1014 | static void elf_write_sections (void) { | |
1015 | int i; | |
1016 | for (i = 0; i < elf_nsect; i++) | |
1017 | if (elf_sects[i].data) { | |
1018 | long len = elf_sects[i].len; | |
1019 | long reallen = (len+SEG_ALIGN_1) & ~SEG_ALIGN_1; | |
1020 | long align = reallen - len; | |
1021 | if (elf_sects[i].is_saa) | |
1022 | saa_fpwrite (elf_sects[i].data, elffp); | |
1023 | else | |
1024 | fwrite (elf_sects[i].data, len, 1, elffp); | |
1025 | fwrite (align_str, align, 1, elffp); | |
1026 | } | |
1027 | } | |
1028 | ||
1029 | static void elf_sect_write (struct Section *sect, | |
1030 | unsigned char *data, unsigned long len) { | |
1031 | saa_wbytes (sect->data, data, len); | |
1032 | sect->len += len; | |
1033 | } | |
1034 | ||
1035 | static long elf_segbase (long segment) { | |
1036 | return segment; | |
1037 | } | |
1038 | ||
1039 | static int elf_directive (char *directive, char *value, int pass) { | |
1040 | return 0; | |
1041 | } | |
1042 | ||
1043 | static void elf_filename (char *inname, char *outname, efunc error) { | |
1044 | strcpy(elf_module, inname); | |
1045 | standard_extension (inname, outname, ".o", error); | |
1046 | } | |
1047 | ||
1048 | static char *elf_stdmac[] = { | |
1049 | "%define __SECT__ [section .text]", | |
1050 | NULL | |
1051 | }; | |
1052 | ||
1053 | struct ofmt of_elf = { | |
1054 | "ELF32 (i386) object files (e.g. Linux)", | |
1055 | "elf", | |
1056 | elf_stdmac, | |
1057 | elf_init, | |
1058 | elf_out, | |
1059 | elf_deflabel, | |
1060 | elf_section_names, | |
1061 | elf_segbase, | |
1062 | elf_directive, | |
1063 | elf_filename, | |
1064 | elf_cleanup | |
1065 | }; | |
1066 | ||
1067 | #endif /* OF_ELF */ |