1 | /* ----------------------------------------------------------------------- * |
2 | * |
3 | * Copyright 1996-2017 The NASM Authors - All Rights Reserved |
4 | * See the file AUTHORS included with the NASM distribution for |
5 | * the specific copyright holders. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following |
9 | * conditions are met: |
10 | * |
11 | * * Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * * Redistributions in binary form must reproduce the above |
14 | * copyright notice, this list of conditions and the following |
15 | * disclaimer in the documentation and/or other materials provided |
16 | * with the distribution. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
19 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
20 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
29 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
30 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | * |
32 | * ----------------------------------------------------------------------- */ |
33 | |
34 | /* |
35 | * Common code for outelf32 and outelf64 |
36 | */ |
37 | |
38 | #include "compiler.h" |
39 | |
40 | #include <stdio.h> |
41 | #include <stdlib.h> |
42 | |
43 | #include "nasm.h" |
44 | #include "nasmlib.h" |
45 | #include "error.h" |
46 | #include "saa.h" |
47 | #include "raa.h" |
48 | #include "stdscan.h" |
49 | #include "eval.h" |
50 | #include "outform.h" |
51 | #include "outlib.h" |
52 | #include "rbtree.h" |
53 | #include "ver.h" |
54 | |
55 | #include "dwarf.h" |
56 | #include "stabs.h" |
57 | #include "outelf.h" |
58 | #include "elf.h" |
59 | |
60 | #if defined(OF_ELF32) || defined(OF_ELF64) || defined(OF_ELFX32) |
61 | |
62 | #define SECT_DELTA 32 |
63 | static struct elf_section **sects; |
64 | static int nsects, sectlen; |
65 | |
66 | #define SHSTR_DELTA 256 |
67 | static char *shstrtab; |
68 | static int shstrtablen, shstrtabsize; |
69 | |
70 | static struct SAA *syms; |
71 | static uint32_t nlocals, nglobs, ndebugs; /* Symbol counts */ |
72 | |
73 | static int32_t def_seg; |
74 | |
75 | static struct RAA *bsym; |
76 | |
77 | static struct SAA *strs; |
78 | static uint32_t strslen; |
79 | |
80 | static struct elf_symbol *fwds; |
81 | |
82 | static char elf_module[FILENAME_MAX]; |
83 | |
84 | extern const struct ofmt of_elf32; |
85 | extern const struct ofmt of_elf64; |
86 | extern const struct ofmt of_elfx32; |
87 | |
88 | static struct ELF_SECTDATA { |
89 | void *data; |
90 | int64_t len; |
91 | bool is_saa; |
92 | } *elf_sects; |
93 | |
94 | static int elf_nsect, nsections; |
95 | static int64_t elf_foffs; |
96 | |
97 | static void elf_write(void); |
98 | static void elf_sect_write(struct elf_section *, const void *, size_t); |
99 | static void elf_sect_writeaddr(struct elf_section *, int64_t, size_t); |
100 | static void elf_section_header(int, int, uint64_t, void *, bool, uint64_t, int, int, |
101 | int, int); |
102 | static void elf_write_sections(void); |
103 | static struct SAA *elf_build_symtab(int32_t *, int32_t *); |
104 | static struct SAA *elf_build_reltab(uint64_t *, struct elf_reloc *); |
105 | static void add_sectname(const char *, const char *); |
106 | |
107 | struct erel { |
108 | int offset; |
109 | int info; |
110 | }; |
111 | |
112 | struct symlininfo { |
113 | int offset; |
114 | int section; /* index into sects[] */ |
115 | int segto; /* internal section number */ |
116 | char *name; /* shallow-copied pointer of section name */ |
117 | }; |
118 | |
119 | struct linelist { |
120 | struct linelist *next; |
121 | struct linelist *last; |
122 | struct symlininfo info; |
123 | char *filename; |
124 | int line; |
125 | }; |
126 | |
127 | struct sectlist { |
128 | struct SAA *psaa; |
129 | int section; |
130 | int line; |
131 | int offset; |
132 | int file; |
133 | struct sectlist *next; |
134 | struct sectlist *last; |
135 | }; |
136 | |
137 | /* common debug variables */ |
138 | static int currentline = 1; |
139 | static int debug_immcall = 0; |
140 | |
141 | /* stabs debug variables */ |
142 | static struct linelist *stabslines = 0; |
143 | static int numlinestabs = 0; |
144 | static char *stabs_filename = 0; |
145 | static uint8_t *stabbuf = 0, *stabstrbuf = 0, *stabrelbuf = 0; |
146 | static int stablen, stabstrlen, stabrellen; |
147 | |
148 | /* dwarf debug variables */ |
149 | static struct linelist *dwarf_flist = 0, *dwarf_clist = 0, *dwarf_elist = 0; |
150 | static struct sectlist *dwarf_fsect = 0, *dwarf_csect = 0, *dwarf_esect = 0; |
151 | static int dwarf_numfiles = 0, dwarf_nsections; |
152 | static uint8_t *arangesbuf = 0, *arangesrelbuf = 0, *pubnamesbuf = 0, *infobuf = 0, *inforelbuf = 0, |
153 | *abbrevbuf = 0, *linebuf = 0, *linerelbuf = 0, *framebuf = 0, *locbuf = 0; |
154 | static int8_t line_base = -5, line_range = 14, opcode_base = 13; |
155 | static int arangeslen, arangesrellen, pubnameslen, infolen, inforellen, |
156 | abbrevlen, linelen, linerellen, framelen, loclen; |
157 | static int64_t dwarf_infosym, dwarf_abbrevsym, dwarf_linesym; |
158 | |
159 | static struct elf_symbol *lastsym; |
160 | |
161 | /* common debugging routines */ |
162 | static void debug_typevalue(int32_t); |
163 | |
164 | /* stabs debugging routines */ |
165 | static void stabs_linenum(const char *filename, int32_t linenumber, int32_t); |
166 | static void stabs_output(int, void *); |
167 | static void stabs_generate(void); |
168 | static void stabs_cleanup(void); |
169 | |
170 | /* dwarf debugging routines */ |
171 | static void dwarf_init(void); |
172 | static void dwarf_linenum(const char *filename, int32_t linenumber, int32_t); |
173 | static void dwarf_output(int, void *); |
174 | static void dwarf_generate(void); |
175 | static void dwarf_cleanup(void); |
176 | static void dwarf_findfile(const char *); |
177 | static void dwarf_findsect(const int); |
178 | |
179 | static bool is_elf64(void); |
180 | static bool is_elf32(void); |
181 | static bool is_elfx32(void); |
182 | |
183 | static bool dfmt_is_stabs(void); |
184 | static bool dfmt_is_dwarf(void); |
185 | |
186 | /* |
187 | * Special NASM section numbers which are used to define ELF special |
188 | * symbols. |
189 | */ |
190 | static int32_t elf_gotpc_sect, elf_gotoff_sect; |
191 | static int32_t elf_got_sect, elf_plt_sect; |
192 | static int32_t elf_sym_sect, elf_gottpoff_sect, elf_tlsie_sect; |
193 | |
194 | uint8_t elf_osabi = 0; /* Default OSABI = 0 (System V or Linux) */ |
195 | uint8_t elf_abiver = 0; /* Current ABI version */ |
196 | |
197 | const struct elf_known_section elf_known_sections[] = { |
198 | { ".text" , SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 16 }, |
199 | { ".rodata" , SHT_PROGBITS, SHF_ALLOC, 4 }, |
200 | { ".lrodata" , SHT_PROGBITS, SHF_ALLOC, 4 }, |
201 | { ".data" , SHT_PROGBITS, SHF_ALLOC|SHF_WRITE, 4 }, |
202 | { ".ldata" , SHT_PROGBITS, SHF_ALLOC|SHF_WRITE, 4 }, |
203 | { ".bss" , SHT_NOBITS, SHF_ALLOC|SHF_WRITE, 4 }, |
204 | { ".lbss" , SHT_NOBITS, SHF_ALLOC|SHF_WRITE, 4 }, |
205 | { ".tdata" , SHT_PROGBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, 4 }, |
206 | { ".tbss" , SHT_NOBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, 4 }, |
207 | { ".comment" , SHT_PROGBITS, 0, 1 }, |
208 | { NULL, SHT_PROGBITS, SHF_ALLOC, 1 } /* default */ |
209 | }; |
210 | |
211 | /* parse section attributes */ |
212 | static void elf_section_attrib(char *name, char *attr, int pass, |
213 | uint32_t *flags_and, uint32_t *flags_or, |
214 | uint64_t *align, int *type) |
215 | { |
216 | char *opt, *val, *next; |
217 | |
218 | opt = nasm_skip_spaces(attr); |
219 | if (!opt || !*opt) |
220 | return; |
221 | |
222 | while ((opt = nasm_opt_val(opt, &val, &next))) { |
223 | if (!nasm_stricmp(opt, "align" )) { |
224 | if (!val) { |
225 | nasm_error(ERR_NONFATAL, |
226 | "section align without value specified" ); |
227 | } else { |
228 | *align = atoi(val); |
229 | if (*align == 0) { |
230 | *align = SHA_ANY; |
231 | } else if (!is_power2(*align)) { |
232 | nasm_error(ERR_NONFATAL, |
233 | "section alignment %" PRId64" is not a power of two" , |
234 | *align); |
235 | *align = SHA_ANY; |
236 | } |
237 | } |
238 | } else if (!nasm_stricmp(opt, "alloc" )) { |
239 | *flags_and |= SHF_ALLOC; |
240 | *flags_or |= SHF_ALLOC; |
241 | } else if (!nasm_stricmp(opt, "noalloc" )) { |
242 | *flags_and |= SHF_ALLOC; |
243 | *flags_or &= ~SHF_ALLOC; |
244 | } else if (!nasm_stricmp(opt, "exec" )) { |
245 | *flags_and |= SHF_EXECINSTR; |
246 | *flags_or |= SHF_EXECINSTR; |
247 | } else if (!nasm_stricmp(opt, "noexec" )) { |
248 | *flags_and |= SHF_EXECINSTR; |
249 | *flags_or &= ~SHF_EXECINSTR; |
250 | } else if (!nasm_stricmp(opt, "write" )) { |
251 | *flags_and |= SHF_WRITE; |
252 | *flags_or |= SHF_WRITE; |
253 | } else if (!nasm_stricmp(opt, "tls" )) { |
254 | *flags_and |= SHF_TLS; |
255 | *flags_or |= SHF_TLS; |
256 | } else if (!nasm_stricmp(opt, "nowrite" )) { |
257 | *flags_and |= SHF_WRITE; |
258 | *flags_or &= ~SHF_WRITE; |
259 | } else if (!nasm_stricmp(opt, "progbits" )) { |
260 | *type = SHT_PROGBITS; |
261 | } else if (!nasm_stricmp(opt, "nobits" )) { |
262 | *type = SHT_NOBITS; |
263 | } else if (pass == 1) { |
264 | nasm_error(ERR_WARNING, |
265 | "Unknown section attribute '%s' ignored on" |
266 | " declaration of section `%s'" , opt, name); |
267 | } |
268 | opt = next; |
269 | } |
270 | } |
271 | |
272 | static enum directive_result |
273 | elf_directive(enum directive directive, char *value, int pass) |
274 | { |
275 | int64_t n; |
276 | bool err; |
277 | char *p; |
278 | |
279 | switch (directive) { |
280 | case D_OSABI: |
281 | if (pass == 2) |
282 | return DIRR_OK; /* ignore in pass 2 */ |
283 | |
284 | n = readnum(value, &err); |
285 | if (err) { |
286 | nasm_error(ERR_NONFATAL, "`osabi' directive requires a parameter" ); |
287 | return DIRR_ERROR; |
288 | } |
289 | |
290 | if (n < 0 || n > 255) { |
291 | nasm_error(ERR_NONFATAL, "valid osabi numbers are 0 to 255" ); |
292 | return DIRR_ERROR; |
293 | } |
294 | |
295 | elf_osabi = n; |
296 | elf_abiver = 0; |
297 | |
298 | p = strchr(value,','); |
299 | if (!p) |
300 | return DIRR_OK; |
301 | |
302 | n = readnum(p + 1, &err); |
303 | if (err || n < 0 || n > 255) { |
304 | nasm_error(ERR_NONFATAL, "invalid ABI version number (valid: 0 to 255)" ); |
305 | return DIRR_ERROR; |
306 | } |
307 | |
308 | elf_abiver = n; |
309 | return DIRR_OK; |
310 | |
311 | default: |
312 | return DIRR_UNKNOWN; |
313 | } |
314 | } |
315 | |
316 | static void elf_init(void) |
317 | { |
318 | strlcpy(elf_module, inname, sizeof(elf_module)); |
319 | sects = NULL; |
320 | nsects = sectlen = 0; |
321 | syms = saa_init((int32_t)sizeof(struct elf_symbol)); |
322 | nlocals = nglobs = ndebugs = 0; |
323 | bsym = raa_init(); |
324 | strs = saa_init(1L); |
325 | saa_wbytes(strs, "\0" , 1L); |
326 | saa_wbytes(strs, elf_module, strlen(elf_module)+1); |
327 | strslen = 2 + strlen(elf_module); |
328 | shstrtab = NULL; |
329 | shstrtablen = shstrtabsize = 0;; |
330 | add_sectname("" , "" ); |
331 | |
332 | fwds = NULL; |
333 | |
334 | /* |
335 | * FIXME: tlsie is Elf32 only and |
336 | * gottpoff is Elfx32|64 only. |
337 | */ |
338 | |
339 | elf_gotpc_sect = seg_alloc(); |
340 | backend_label("..gotpc" , elf_gotpc_sect + 1, 0L); |
341 | elf_gotoff_sect = seg_alloc(); |
342 | backend_label("..gotoff" , elf_gotoff_sect + 1, 0L); |
343 | elf_got_sect = seg_alloc(); |
344 | backend_label("..got" , elf_got_sect + 1, 0L); |
345 | elf_plt_sect = seg_alloc(); |
346 | backend_label("..plt" , elf_plt_sect + 1, 0L); |
347 | elf_sym_sect = seg_alloc(); |
348 | backend_label("..sym" , elf_sym_sect + 1, 0L); |
349 | elf_gottpoff_sect = seg_alloc(); |
350 | backend_label("..gottpoff" , elf_gottpoff_sect + 1, 0L); |
351 | elf_tlsie_sect = seg_alloc(); |
352 | backend_label("..tlsie" , elf_tlsie_sect + 1, 0L); |
353 | |
354 | def_seg = seg_alloc(); |
355 | } |
356 | |
357 | static void elf_cleanup(void) |
358 | { |
359 | struct elf_reloc *r; |
360 | int i; |
361 | |
362 | elf_write(); |
363 | for (i = 0; i < nsects; i++) { |
364 | if (sects[i]->type != SHT_NOBITS) |
365 | saa_free(sects[i]->data); |
366 | if (sects[i]->head) |
367 | saa_free(sects[i]->rel); |
368 | while (sects[i]->head) { |
369 | r = sects[i]->head; |
370 | sects[i]->head = sects[i]->head->next; |
371 | nasm_free(r); |
372 | } |
373 | } |
374 | nasm_free(sects); |
375 | saa_free(syms); |
376 | raa_free(bsym); |
377 | saa_free(strs); |
378 | dfmt->cleanup(); |
379 | } |
380 | |
381 | /* add entry to the elf .shstrtab section */ |
382 | static void add_sectname(const char *firsthalf, const char *secondhalf) |
383 | { |
384 | int len = strlen(firsthalf) + strlen(secondhalf); |
385 | while (shstrtablen + len + 1 > shstrtabsize) |
386 | shstrtab = nasm_realloc(shstrtab, (shstrtabsize += SHSTR_DELTA)); |
387 | strcpy(shstrtab + shstrtablen, firsthalf); |
388 | strcat(shstrtab + shstrtablen, secondhalf); |
389 | shstrtablen += len + 1; |
390 | } |
391 | |
392 | static int elf_make_section(char *name, int type, int flags, int align) |
393 | { |
394 | struct elf_section *s; |
395 | |
396 | s = nasm_zalloc(sizeof(*s)); |
397 | |
398 | if (type != SHT_NOBITS) |
399 | s->data = saa_init(1L); |
400 | s->tail = &s->head; |
401 | if (!strcmp(name, ".text" )) |
402 | s->index = def_seg; |
403 | else |
404 | s->index = seg_alloc(); |
405 | add_sectname("" , name); |
406 | |
407 | s->name = nasm_strdup(name); |
408 | s->type = type; |
409 | s->flags = flags; |
410 | s->align = align; |
411 | |
412 | if (nsects >= sectlen) |
413 | sects = nasm_realloc(sects, (sectlen += SECT_DELTA) * sizeof(*sects)); |
414 | sects[nsects++] = s; |
415 | |
416 | return nsects - 1; |
417 | } |
418 | |
419 | static int32_t elf_section_names(char *name, int pass, int *bits) |
420 | { |
421 | char *p; |
422 | uint32_t flags, flags_and, flags_or; |
423 | uint64_t align; |
424 | int type, i; |
425 | |
426 | if (!name) { |
427 | *bits = ofmt->maxbits; |
428 | return def_seg; |
429 | } |
430 | |
431 | p = nasm_skip_word(name); |
432 | if (*p) |
433 | *p++ = '\0'; |
434 | flags_and = flags_or = type = align = 0; |
435 | |
436 | elf_section_attrib(name, p, pass, &flags_and, |
437 | &flags_or, &align, &type); |
438 | |
439 | if (!strcmp(name, ".shstrtab" ) || |
440 | !strcmp(name, ".symtab" ) || |
441 | !strcmp(name, ".strtab" )) { |
442 | nasm_error(ERR_NONFATAL, "attempt to redefine reserved section" |
443 | "name `%s'" , name); |
444 | return NO_SEG; |
445 | } |
446 | |
447 | for (i = 0; i < nsects; i++) |
448 | if (!strcmp(name, sects[i]->name)) |
449 | break; |
450 | if (i == nsects) { |
451 | const struct elf_known_section *ks = elf_known_sections; |
452 | |
453 | while (ks->name) { |
454 | if (!strcmp(name, ks->name)) |
455 | break; |
456 | ks++; |
457 | } |
458 | |
459 | type = type ? type : ks->type; |
460 | align = align ? align : ks->align; |
461 | flags = (ks->flags & ~flags_and) | flags_or; |
462 | |
463 | i = elf_make_section(name, type, flags, align); |
464 | } else if (pass == 1) { |
465 | if ((type && sects[i]->type != type) |
466 | || (align && sects[i]->align != align) |
467 | || (flags_and && ((sects[i]->flags & flags_and) != flags_or))) |
468 | nasm_error(ERR_WARNING, "incompatible section attributes ignored on" |
469 | " redeclaration of section `%s'" , name); |
470 | } |
471 | |
472 | return sects[i]->index; |
473 | } |
474 | |
475 | static void elf_deflabel(char *name, int32_t segment, int64_t offset, |
476 | int is_global, char *special) |
477 | { |
478 | int pos = strslen; |
479 | struct elf_symbol *sym; |
480 | bool special_used = false; |
481 | |
482 | #if defined(DEBUG) && DEBUG>2 |
483 | nasm_error(ERR_DEBUG, |
484 | " elf_deflabel: %s, seg=%" PRIx32", off=%" PRIx64", is_global=%d, %s\n" , |
485 | name, segment, offset, is_global, special); |
486 | #endif |
487 | if (name[0] == '.' && name[1] == '.' && name[2] != '@') { |
488 | /* |
489 | * This is a NASM special symbol. We never allow it into |
490 | * the ELF symbol table, even if it's a valid one. If it |
491 | * _isn't_ a valid one, we should barf immediately. |
492 | * |
493 | * FIXME: tlsie is Elf32 only, and gottpoff is Elfx32|64 only. |
494 | */ |
495 | if (strcmp(name, "..gotpc" ) && strcmp(name, "..gotoff" ) && |
496 | strcmp(name, "..got" ) && strcmp(name, "..plt" ) && |
497 | strcmp(name, "..sym" ) && strcmp(name, "..gottpoff" ) && |
498 | strcmp(name, "..tlsie" )) |
499 | nasm_error(ERR_NONFATAL, "unrecognised special symbol `%s'" , name); |
500 | return; |
501 | } |
502 | |
503 | if (is_global == 3) { |
504 | struct elf_symbol **s; |
505 | /* |
506 | * Fix up a forward-reference symbol size from the first |
507 | * pass. |
508 | */ |
509 | for (s = &fwds; *s; s = &(*s)->nextfwd) |
510 | if (!strcmp((*s)->name, name)) { |
511 | struct tokenval tokval; |
512 | expr *e; |
513 | char *p = nasm_skip_spaces(nasm_skip_word(special)); |
514 | |
515 | stdscan_reset(); |
516 | stdscan_set(p); |
517 | tokval.t_type = TOKEN_INVALID; |
518 | e = evaluate(stdscan, NULL, &tokval, NULL, 1, NULL); |
519 | if (e) { |
520 | if (!is_simple(e)) |
521 | nasm_error(ERR_NONFATAL, "cannot use relocatable" |
522 | " expression as symbol size" ); |
523 | else |
524 | (*s)->size = reloc_value(e); |
525 | } |
526 | |
527 | /* |
528 | * Remove it from the list of unresolved sizes. |
529 | */ |
530 | nasm_free((*s)->name); |
531 | *s = (*s)->nextfwd; |
532 | return; |
533 | } |
534 | return; /* it wasn't an important one */ |
535 | } |
536 | |
537 | saa_wbytes(strs, name, (int32_t)(1 + strlen(name))); |
538 | strslen += 1 + strlen(name); |
539 | |
540 | lastsym = sym = saa_wstruct(syms); |
541 | |
542 | memset(&sym->symv, 0, sizeof(struct rbtree)); |
543 | |
544 | sym->strpos = pos; |
545 | sym->type = is_global ? SYM_GLOBAL : SYM_LOCAL; |
546 | sym->other = STV_DEFAULT; |
547 | sym->size = 0; |
548 | if (segment == NO_SEG) |
549 | sym->section = SHN_ABS; |
550 | else { |
551 | int i; |
552 | sym->section = SHN_UNDEF; |
553 | if (segment == def_seg) { |
554 | /* we have to be sure at least text section is there */ |
555 | int tempint; |
556 | if (segment != elf_section_names(".text" , 2, &tempint)) |
557 | nasm_panic(0, "strange segment conditions in ELF driver" ); |
558 | } |
559 | for (i = 0; i < nsects; i++) { |
560 | if (segment == sects[i]->index) { |
561 | sym->section = i + 1; |
562 | break; |
563 | } |
564 | } |
565 | } |
566 | |
567 | if (is_global == 2) { |
568 | sym->size = offset; |
569 | sym->symv.key = 0; |
570 | sym->section = SHN_COMMON; |
571 | /* |
572 | * We have a common variable. Check the special text to see |
573 | * if it's a valid number and power of two; if so, store it |
574 | * as the alignment for the common variable. |
575 | */ |
576 | if (special) { |
577 | bool err; |
578 | sym->symv.key = readnum(special, &err); |
579 | if (err) |
580 | nasm_error(ERR_NONFATAL, "alignment constraint `%s' is not a" |
581 | " valid number" , special); |
582 | else if ((sym->symv.key | (sym->symv.key - 1)) != 2 * sym->symv.key - 1) |
583 | nasm_error(ERR_NONFATAL, "alignment constraint `%s' is not a" |
584 | " power of two" , special); |
585 | } |
586 | special_used = true; |
587 | } else |
588 | sym->symv.key = (sym->section == SHN_UNDEF ? 0 : offset); |
589 | |
590 | if (sym->type == SYM_GLOBAL) { |
591 | /* |
592 | * If sym->section == SHN_ABS, then the first line of the |
593 | * else section would cause a core dump, because its a reference |
594 | * beyond the end of the section array. |
595 | * This behaviour is exhibited by this code: |
596 | * GLOBAL crash_nasm |
597 | * crash_nasm equ 0 |
598 | * To avoid such a crash, such requests are silently discarded. |
599 | * This may not be the best solution. |
600 | */ |
601 | if (sym->section == SHN_UNDEF || sym->section == SHN_COMMON) { |
602 | bsym = raa_write(bsym, segment, nglobs); |
603 | } else if (sym->section != SHN_ABS) { |
604 | /* |
605 | * This is a global symbol; so we must add it to the rbtree |
606 | * of global symbols in its section. |
607 | * |
608 | * In addition, we check the special text for symbol |
609 | * type and size information. |
610 | */ |
611 | sects[sym->section-1]->gsyms = |
612 | rb_insert(sects[sym->section-1]->gsyms, &sym->symv); |
613 | |
614 | if (special) { |
615 | int n = strcspn(special, " \t" ); |
616 | |
617 | if (!nasm_strnicmp(special, "function" , n)) |
618 | sym->type |= STT_FUNC; |
619 | else if (!nasm_strnicmp(special, "data" , n) || |
620 | !nasm_strnicmp(special, "object" , n)) |
621 | sym->type |= STT_OBJECT; |
622 | else if (!nasm_strnicmp(special, "notype" , n)) |
623 | sym->type |= STT_NOTYPE; |
624 | else |
625 | nasm_error(ERR_NONFATAL, "unrecognised symbol type `%.*s'" , |
626 | n, special); |
627 | special += n; |
628 | |
629 | special = nasm_skip_spaces(special); |
630 | if (*special) { |
631 | n = strcspn(special, " \t" ); |
632 | if (!nasm_strnicmp(special, "default" , n)) |
633 | sym->other = STV_DEFAULT; |
634 | else if (!nasm_strnicmp(special, "internal" , n)) |
635 | sym->other = STV_INTERNAL; |
636 | else if (!nasm_strnicmp(special, "hidden" , n)) |
637 | sym->other = STV_HIDDEN; |
638 | else if (!nasm_strnicmp(special, "protected" , n)) |
639 | sym->other = STV_PROTECTED; |
640 | else |
641 | n = 0; |
642 | special += n; |
643 | } |
644 | |
645 | if (*special) { |
646 | struct tokenval tokval; |
647 | expr *e; |
648 | int fwd = 0; |
649 | char *saveme = stdscan_get(); |
650 | |
651 | while (special[n] && nasm_isspace(special[n])) |
652 | n++; |
653 | /* |
654 | * We have a size expression; attempt to |
655 | * evaluate it. |
656 | */ |
657 | stdscan_reset(); |
658 | stdscan_set(special + n); |
659 | tokval.t_type = TOKEN_INVALID; |
660 | e = evaluate(stdscan, NULL, &tokval, &fwd, 0, NULL); |
661 | if (fwd) { |
662 | sym->nextfwd = fwds; |
663 | fwds = sym; |
664 | sym->name = nasm_strdup(name); |
665 | } else if (e) { |
666 | if (!is_simple(e)) |
667 | nasm_error(ERR_NONFATAL, "cannot use relocatable" |
668 | " expression as symbol size" ); |
669 | else |
670 | sym->size = reloc_value(e); |
671 | } |
672 | stdscan_set(saveme); |
673 | } |
674 | special_used = true; |
675 | } |
676 | /* |
677 | * If TLS segment, mark symbol accordingly. |
678 | */ |
679 | if (sects[sym->section - 1]->flags & SHF_TLS) { |
680 | sym->type &= 0xf0; |
681 | sym->type |= STT_TLS; |
682 | } |
683 | } |
684 | sym->globnum = nglobs; |
685 | nglobs++; |
686 | } else |
687 | nlocals++; |
688 | |
689 | if (special && !special_used) |
690 | nasm_error(ERR_NONFATAL, "no special symbol features supported here" ); |
691 | } |
692 | |
693 | static void elf_add_reloc(struct elf_section *sect, int32_t segment, |
694 | int64_t offset, int type) |
695 | { |
696 | struct elf_reloc *r; |
697 | |
698 | r = *sect->tail = nasm_zalloc(sizeof(struct elf_reloc)); |
699 | sect->tail = &r->next; |
700 | |
701 | r->address = sect->len; |
702 | r->offset = offset; |
703 | |
704 | if (segment != NO_SEG) { |
705 | int i; |
706 | for (i = 0; i < nsects; i++) |
707 | if (segment == sects[i]->index) |
708 | r->symbol = i + 2; |
709 | if (!r->symbol) |
710 | r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment); |
711 | } |
712 | r->type = type; |
713 | |
714 | sect->nrelocs++; |
715 | } |
716 | |
717 | /* |
718 | * This routine deals with ..got and ..sym relocations: the more |
719 | * complicated kinds. In shared-library writing, some relocations |
720 | * with respect to global symbols must refer to the precise symbol |
721 | * rather than referring to an offset from the base of the section |
722 | * _containing_ the symbol. Such relocations call to this routine, |
723 | * which searches the symbol list for the symbol in question. |
724 | * |
725 | * R_386_GOT32 | R_X86_64_GOT32 references require the _exact_ symbol address to be |
726 | * used; R_386_32 | R_X86_64_32 references can be at an offset from the symbol. |
727 | * The boolean argument `exact' tells us this. |
728 | * |
729 | * Return value is the adjusted value of `addr', having become an |
730 | * offset from the symbol rather than the section. Should always be |
731 | * zero when returning from an exact call. |
732 | * |
733 | * Limitation: if you define two symbols at the same place, |
734 | * confusion will occur. |
735 | * |
736 | * Inefficiency: we search, currently, using a linked list which |
737 | * isn't even necessarily sorted. |
738 | */ |
739 | static int64_t elf_add_gsym_reloc(struct elf_section *sect, |
740 | int32_t segment, uint64_t offset, |
741 | int64_t pcrel, int type, bool exact) |
742 | { |
743 | struct elf_reloc *r; |
744 | struct elf_section *s; |
745 | struct elf_symbol *sym; |
746 | struct rbtree *srb; |
747 | int i; |
748 | |
749 | /* |
750 | * First look up the segment/offset pair and find a global |
751 | * symbol corresponding to it. If it's not one of our segments, |
752 | * then it must be an external symbol, in which case we're fine |
753 | * doing a normal elf_add_reloc after first sanity-checking |
754 | * that the offset from the symbol is zero. |
755 | */ |
756 | s = NULL; |
757 | for (i = 0; i < nsects; i++) |
758 | if (segment == sects[i]->index) { |
759 | s = sects[i]; |
760 | break; |
761 | } |
762 | |
763 | if (!s) { |
764 | if (exact && offset) |
765 | nasm_error(ERR_NONFATAL, "invalid access to an external symbol" ); |
766 | else |
767 | elf_add_reloc(sect, segment, offset - pcrel, type); |
768 | return 0; |
769 | } |
770 | |
771 | srb = rb_search(s->gsyms, offset); |
772 | if (!srb || (exact && srb->key != offset)) { |
773 | nasm_error(ERR_NONFATAL, "unable to find a suitable global symbol" |
774 | " for this reference" ); |
775 | return 0; |
776 | } |
777 | sym = container_of(srb, struct elf_symbol, symv); |
778 | |
779 | r = *sect->tail = nasm_malloc(sizeof(struct elf_reloc)); |
780 | sect->tail = &r->next; |
781 | |
782 | r->next = NULL; |
783 | r->address = sect->len; |
784 | r->offset = offset - pcrel - sym->symv.key; |
785 | r->symbol = GLOBAL_TEMP_BASE + sym->globnum; |
786 | r->type = type; |
787 | |
788 | sect->nrelocs++; |
789 | return r->offset; |
790 | } |
791 | |
792 | static void elf32_out(int32_t segto, const void *data, |
793 | enum out_type type, uint64_t size, |
794 | int32_t segment, int32_t wrt) |
795 | { |
796 | struct elf_section *s; |
797 | int64_t addr; |
798 | int reltype, bytes; |
799 | int i; |
800 | static struct symlininfo sinfo; |
801 | |
802 | /* |
803 | * handle absolute-assembly (structure definitions) |
804 | */ |
805 | if (segto == NO_SEG) { |
806 | if (type != OUT_RESERVE) |
807 | nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" |
808 | " space" ); |
809 | return; |
810 | } |
811 | |
812 | s = NULL; |
813 | for (i = 0; i < nsects; i++) |
814 | if (segto == sects[i]->index) { |
815 | s = sects[i]; |
816 | break; |
817 | } |
818 | if (!s) { |
819 | int tempint; /* ignored */ |
820 | if (segto != elf_section_names(".text" , 2, &tempint)) |
821 | nasm_panic(0, "strange segment conditions in ELF driver" ); |
822 | else { |
823 | s = sects[nsects - 1]; |
824 | i = nsects - 1; |
825 | } |
826 | } |
827 | |
828 | /* again some stabs debugging stuff */ |
829 | sinfo.offset = s->len; |
830 | sinfo.section = i; |
831 | sinfo.segto = segto; |
832 | sinfo.name = s->name; |
833 | dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo); |
834 | /* end of debugging stuff */ |
835 | |
836 | if (s->type == SHT_NOBITS && type != OUT_RESERVE) { |
837 | nasm_error(ERR_WARNING, "attempt to initialize memory in" |
838 | " BSS section `%s': ignored" , s->name); |
839 | s->len += realsize(type, size); |
840 | return; |
841 | } |
842 | |
843 | switch (type) { |
844 | case OUT_RESERVE: |
845 | if (s->type == SHT_PROGBITS) { |
846 | nasm_error(ERR_WARNING, "uninitialized space declared in" |
847 | " non-BSS section `%s': zeroing" , s->name); |
848 | elf_sect_write(s, NULL, size); |
849 | } else |
850 | s->len += size; |
851 | break; |
852 | |
853 | case OUT_RAWDATA: |
854 | if (segment != NO_SEG) |
855 | nasm_panic(0, "OUT_RAWDATA with other than NO_SEG" ); |
856 | elf_sect_write(s, data, size); |
857 | break; |
858 | |
859 | case OUT_ADDRESS: |
860 | { |
861 | bool gnu16 = false; |
862 | int asize = abs((int)size); |
863 | |
864 | addr = *(int64_t *)data; |
865 | if (segment != NO_SEG) { |
866 | if (segment % 2) { |
867 | nasm_error(ERR_NONFATAL, "ELF format does not support" |
868 | " segment base references" ); |
869 | } else { |
870 | if (wrt == NO_SEG) { |
871 | /* |
872 | * The if() is a hack to deal with compilers which |
873 | * don't handle switch() statements with 64-bit |
874 | * expressions. |
875 | */ |
876 | switch (asize) { |
877 | case 1: |
878 | gnu16 = true; |
879 | elf_add_reloc(s, segment, 0, R_386_8); |
880 | break; |
881 | case 2: |
882 | gnu16 = true; |
883 | elf_add_reloc(s, segment, 0, R_386_16); |
884 | break; |
885 | case 4: |
886 | elf_add_reloc(s, segment, 0, R_386_32); |
887 | break; |
888 | default: /* Error issued further down */ |
889 | break; |
890 | } |
891 | } else if (wrt == elf_gotpc_sect + 1) { |
892 | /* |
893 | * The user will supply GOT relative to $$. ELF |
894 | * will let us have GOT relative to $. So we |
895 | * need to fix up the data item by $-$$. |
896 | */ |
897 | addr += s->len; |
898 | elf_add_reloc(s, segment, 0, R_386_GOTPC); |
899 | } else if (wrt == elf_gotoff_sect + 1) { |
900 | elf_add_reloc(s, segment, 0, R_386_GOTOFF); |
901 | } else if (wrt == elf_tlsie_sect + 1) { |
902 | addr = elf_add_gsym_reloc(s, segment, addr, 0, |
903 | R_386_TLS_IE, true); |
904 | } else if (wrt == elf_got_sect + 1) { |
905 | addr = elf_add_gsym_reloc(s, segment, addr, 0, |
906 | R_386_GOT32, true); |
907 | } else if (wrt == elf_sym_sect + 1) { |
908 | switch (asize) { |
909 | case 1: |
910 | gnu16 = true; |
911 | addr = elf_add_gsym_reloc(s, segment, addr, 0, |
912 | R_386_8, false); |
913 | break; |
914 | case 2: |
915 | gnu16 = true; |
916 | addr = elf_add_gsym_reloc(s, segment, addr, 0, |
917 | R_386_16, false); |
918 | break; |
919 | case 4: |
920 | addr = elf_add_gsym_reloc(s, segment, addr, 0, |
921 | R_386_32, false); |
922 | break; |
923 | default: |
924 | break; |
925 | } |
926 | } else if (wrt == elf_plt_sect + 1) { |
927 | nasm_error(ERR_NONFATAL, "ELF format cannot produce non-PC-" |
928 | "relative PLT references" ); |
929 | } else { |
930 | nasm_error(ERR_NONFATAL, "ELF format does not support this" |
931 | " use of WRT" ); |
932 | wrt = NO_SEG; /* we can at least _try_ to continue */ |
933 | } |
934 | } |
935 | } |
936 | |
937 | if (gnu16) { |
938 | nasm_error(ERR_WARNING | WARN_GNUELF, |
939 | "8- or 16-bit relocations in ELF32 is a GNU extension" ); |
940 | } else if (asize != 4 && segment != NO_SEG) { |
941 | nasm_error(ERR_NONFATAL, "Unsupported non-32-bit ELF relocation" ); |
942 | } |
943 | elf_sect_writeaddr(s, addr, asize); |
944 | break; |
945 | } |
946 | |
947 | case OUT_REL1ADR: |
948 | reltype = R_386_PC8; |
949 | bytes = 1; |
950 | goto rel12adr; |
951 | case OUT_REL2ADR: |
952 | reltype = R_386_PC16; |
953 | bytes = 2; |
954 | goto rel12adr; |
955 | |
956 | rel12adr: |
957 | addr = *(int64_t *)data - size; |
958 | nasm_assert(segment != segto); |
959 | if (segment != NO_SEG && segment % 2) { |
960 | nasm_error(ERR_NONFATAL, "ELF format does not support" |
961 | " segment base references" ); |
962 | } else { |
963 | if (wrt == NO_SEG) { |
964 | nasm_error(ERR_WARNING | WARN_GNUELF, |
965 | "8- or 16-bit relocations in ELF is a GNU extension" ); |
966 | elf_add_reloc(s, segment, 0, reltype); |
967 | } else { |
968 | nasm_error(ERR_NONFATAL, |
969 | "Unsupported non-32-bit ELF relocation" ); |
970 | } |
971 | } |
972 | elf_sect_writeaddr(s, addr, bytes); |
973 | break; |
974 | |
975 | case OUT_REL4ADR: |
976 | addr = *(int64_t *)data - size; |
977 | if (segment == segto) |
978 | nasm_panic(0, "intra-segment OUT_REL4ADR" ); |
979 | if (segment != NO_SEG && segment % 2) { |
980 | nasm_error(ERR_NONFATAL, "ELF format does not support" |
981 | " segment base references" ); |
982 | } else { |
983 | if (wrt == NO_SEG) { |
984 | elf_add_reloc(s, segment, 0, R_386_PC32); |
985 | } else if (wrt == elf_plt_sect + 1) { |
986 | elf_add_reloc(s, segment, 0, R_386_PLT32); |
987 | } else if (wrt == elf_gotpc_sect + 1 || |
988 | wrt == elf_gotoff_sect + 1 || |
989 | wrt == elf_got_sect + 1) { |
990 | nasm_error(ERR_NONFATAL, "ELF format cannot produce PC-" |
991 | "relative GOT references" ); |
992 | } else { |
993 | nasm_error(ERR_NONFATAL, "ELF format does not support this" |
994 | " use of WRT" ); |
995 | wrt = NO_SEG; /* we can at least _try_ to continue */ |
996 | } |
997 | } |
998 | elf_sect_writeaddr(s, addr, 4); |
999 | break; |
1000 | |
1001 | case OUT_REL8ADR: |
1002 | nasm_error(ERR_NONFATAL, "32-bit ELF format does not support 64-bit relocations" ); |
1003 | addr = 0; |
1004 | elf_sect_writeaddr(s, addr, 8); |
1005 | break; |
1006 | |
1007 | default: |
1008 | panic(); |
1009 | } |
1010 | } |
1011 | static void elf64_out(int32_t segto, const void *data, |
1012 | enum out_type type, uint64_t size, |
1013 | int32_t segment, int32_t wrt) |
1014 | { |
1015 | struct elf_section *s; |
1016 | int64_t addr; |
1017 | int reltype, bytes; |
1018 | int i; |
1019 | static struct symlininfo sinfo; |
1020 | |
1021 | /* |
1022 | * handle absolute-assembly (structure definitions) |
1023 | */ |
1024 | if (segto == NO_SEG) { |
1025 | if (type != OUT_RESERVE) |
1026 | nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" |
1027 | " space" ); |
1028 | return; |
1029 | } |
1030 | |
1031 | s = NULL; |
1032 | for (i = 0; i < nsects; i++) |
1033 | if (segto == sects[i]->index) { |
1034 | s = sects[i]; |
1035 | break; |
1036 | } |
1037 | if (!s) { |
1038 | int tempint; /* ignored */ |
1039 | if (segto != elf_section_names(".text" , 2, &tempint)) |
1040 | nasm_panic(0, "strange segment conditions in ELF driver" ); |
1041 | else { |
1042 | s = sects[nsects - 1]; |
1043 | i = nsects - 1; |
1044 | } |
1045 | } |
1046 | |
1047 | /* again some stabs debugging stuff */ |
1048 | sinfo.offset = s->len; |
1049 | sinfo.section = i; |
1050 | sinfo.segto = segto; |
1051 | sinfo.name = s->name; |
1052 | dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo); |
1053 | /* end of debugging stuff */ |
1054 | |
1055 | if (s->type == SHT_NOBITS && type != OUT_RESERVE) { |
1056 | nasm_error(ERR_WARNING, "attempt to initialize memory in" |
1057 | " BSS section `%s': ignored" , s->name); |
1058 | s->len += realsize(type, size); |
1059 | return; |
1060 | } |
1061 | |
1062 | switch (type) { |
1063 | case OUT_RESERVE: |
1064 | if (s->type == SHT_PROGBITS) { |
1065 | nasm_error(ERR_WARNING, "uninitialized space declared in" |
1066 | " non-BSS section `%s': zeroing" , s->name); |
1067 | elf_sect_write(s, NULL, size); |
1068 | } else |
1069 | s->len += size; |
1070 | break; |
1071 | |
1072 | case OUT_RAWDATA: |
1073 | if (segment != NO_SEG) |
1074 | nasm_panic(0, "OUT_RAWDATA with other than NO_SEG" ); |
1075 | elf_sect_write(s, data, size); |
1076 | break; |
1077 | |
1078 | case OUT_ADDRESS: |
1079 | { |
1080 | int isize = (int)size; |
1081 | int asize = abs((int)size); |
1082 | |
1083 | addr = *(int64_t *)data; |
1084 | if (segment == NO_SEG) { |
1085 | /* Do nothing */ |
1086 | } else if (segment % 2) { |
1087 | nasm_error(ERR_NONFATAL, "ELF format does not support" |
1088 | " segment base references" ); |
1089 | } else { |
1090 | if (wrt == NO_SEG) { |
1091 | switch (isize) { |
1092 | case 1: |
1093 | case -1: |
1094 | elf_add_reloc(s, segment, addr, R_X86_64_8); |
1095 | break; |
1096 | case 2: |
1097 | case -2: |
1098 | elf_add_reloc(s, segment, addr, R_X86_64_16); |
1099 | break; |
1100 | case 4: |
1101 | elf_add_reloc(s, segment, addr, R_X86_64_32); |
1102 | break; |
1103 | case -4: |
1104 | elf_add_reloc(s, segment, addr, R_X86_64_32S); |
1105 | break; |
1106 | case 8: |
1107 | case -8: |
1108 | elf_add_reloc(s, segment, addr, R_X86_64_64); |
1109 | break; |
1110 | default: |
1111 | nasm_panic(0, "internal error elf64-hpa-871" ); |
1112 | break; |
1113 | } |
1114 | addr = 0; |
1115 | } else if (wrt == elf_gotpc_sect + 1) { |
1116 | /* |
1117 | * The user will supply GOT relative to $$. ELF |
1118 | * will let us have GOT relative to $. So we |
1119 | * need to fix up the data item by $-$$. |
1120 | */ |
1121 | addr += s->len; |
1122 | elf_add_reloc(s, segment, addr, R_X86_64_GOTPC32); |
1123 | addr = 0; |
1124 | } else if (wrt == elf_gotoff_sect + 1) { |
1125 | if (asize != 8) { |
1126 | nasm_error(ERR_NONFATAL, "ELF64 requires ..gotoff " |
1127 | "references to be qword" ); |
1128 | } else { |
1129 | elf_add_reloc(s, segment, addr, R_X86_64_GOTOFF64); |
1130 | addr = 0; |
1131 | } |
1132 | } else if (wrt == elf_got_sect + 1) { |
1133 | switch (asize) { |
1134 | case 4: |
1135 | elf_add_gsym_reloc(s, segment, addr, 0, |
1136 | R_X86_64_GOT32, true); |
1137 | addr = 0; |
1138 | break; |
1139 | case 8: |
1140 | elf_add_gsym_reloc(s, segment, addr, 0, |
1141 | R_X86_64_GOT64, true); |
1142 | addr = 0; |
1143 | break; |
1144 | default: |
1145 | nasm_error(ERR_NONFATAL, "invalid ..got reference" ); |
1146 | break; |
1147 | } |
1148 | } else if (wrt == elf_sym_sect + 1) { |
1149 | switch (isize) { |
1150 | case 1: |
1151 | case -1: |
1152 | elf_add_gsym_reloc(s, segment, addr, 0, |
1153 | R_X86_64_8, false); |
1154 | addr = 0; |
1155 | break; |
1156 | case 2: |
1157 | case -2: |
1158 | elf_add_gsym_reloc(s, segment, addr, 0, |
1159 | R_X86_64_16, false); |
1160 | addr = 0; |
1161 | break; |
1162 | case 4: |
1163 | elf_add_gsym_reloc(s, segment, addr, 0, |
1164 | R_X86_64_32, false); |
1165 | addr = 0; |
1166 | break; |
1167 | case -4: |
1168 | elf_add_gsym_reloc(s, segment, addr, 0, |
1169 | R_X86_64_32S, false); |
1170 | addr = 0; |
1171 | break; |
1172 | case 8: |
1173 | case -8: |
1174 | elf_add_gsym_reloc(s, segment, addr, 0, |
1175 | R_X86_64_64, false); |
1176 | addr = 0; |
1177 | break; |
1178 | default: |
1179 | nasm_panic(0, "internal error elf64-hpa-903" ); |
1180 | break; |
1181 | } |
1182 | } else if (wrt == elf_plt_sect + 1) { |
1183 | nasm_error(ERR_NONFATAL, "ELF format cannot produce non-PC-" |
1184 | "relative PLT references" ); |
1185 | } else { |
1186 | nasm_error(ERR_NONFATAL, "ELF format does not support this" |
1187 | " use of WRT" ); |
1188 | } |
1189 | } |
1190 | elf_sect_writeaddr(s, addr, asize); |
1191 | break; |
1192 | } |
1193 | |
1194 | case OUT_REL1ADR: |
1195 | reltype = R_X86_64_PC8; |
1196 | bytes = 1; |
1197 | goto rel12adr; |
1198 | |
1199 | case OUT_REL2ADR: |
1200 | reltype = R_X86_64_PC16; |
1201 | bytes = 2; |
1202 | goto rel12adr; |
1203 | |
1204 | rel12adr: |
1205 | addr = *(int64_t *)data - size; |
1206 | if (segment == segto) |
1207 | nasm_panic(0, "intra-segment OUT_REL1ADR" ); |
1208 | if (segment == NO_SEG) { |
1209 | /* Do nothing */ |
1210 | } else if (segment % 2) { |
1211 | nasm_error(ERR_NONFATAL, "ELF format does not support" |
1212 | " segment base references" ); |
1213 | } else { |
1214 | if (wrt == NO_SEG) { |
1215 | elf_add_reloc(s, segment, addr, reltype); |
1216 | addr = 0; |
1217 | } else { |
1218 | nasm_error(ERR_NONFATAL, |
1219 | "Unsupported non-32-bit ELF relocation" ); |
1220 | } |
1221 | } |
1222 | elf_sect_writeaddr(s, addr, bytes); |
1223 | break; |
1224 | |
1225 | case OUT_REL4ADR: |
1226 | addr = *(int64_t *)data - size; |
1227 | if (segment == segto) |
1228 | nasm_panic(0, "intra-segment OUT_REL4ADR" ); |
1229 | if (segment == NO_SEG) { |
1230 | /* Do nothing */ |
1231 | } else if (segment % 2) { |
1232 | nasm_error(ERR_NONFATAL, "ELF64 format does not support" |
1233 | " segment base references" ); |
1234 | } else { |
1235 | if (wrt == NO_SEG) { |
1236 | elf_add_reloc(s, segment, addr, R_X86_64_PC32); |
1237 | addr = 0; |
1238 | } else if (wrt == elf_plt_sect + 1) { |
1239 | elf_add_gsym_reloc(s, segment, addr+size, size, |
1240 | R_X86_64_PLT32, true); |
1241 | addr = 0; |
1242 | } else if (wrt == elf_gotpc_sect + 1 || |
1243 | wrt == elf_got_sect + 1) { |
1244 | elf_add_gsym_reloc(s, segment, addr+size, size, |
1245 | R_X86_64_GOTPCREL, true); |
1246 | addr = 0; |
1247 | } else if (wrt == elf_gotoff_sect + 1 || |
1248 | wrt == elf_got_sect + 1) { |
1249 | nasm_error(ERR_NONFATAL, "ELF64 requires ..gotoff references to be " |
1250 | "qword absolute" ); |
1251 | } else if (wrt == elf_gottpoff_sect + 1) { |
1252 | elf_add_gsym_reloc(s, segment, addr+size, size, |
1253 | R_X86_64_GOTTPOFF, true); |
1254 | addr = 0; |
1255 | } else { |
1256 | nasm_error(ERR_NONFATAL, "ELF64 format does not support this" |
1257 | " use of WRT" ); |
1258 | } |
1259 | } |
1260 | elf_sect_writeaddr(s, addr, 4); |
1261 | break; |
1262 | |
1263 | case OUT_REL8ADR: |
1264 | addr = *(int64_t *)data - size; |
1265 | if (segment == segto) |
1266 | nasm_panic(0, "intra-segment OUT_REL8ADR" ); |
1267 | if (segment == NO_SEG) { |
1268 | /* Do nothing */ |
1269 | } else if (segment % 2) { |
1270 | nasm_error(ERR_NONFATAL, "ELF64 format does not support" |
1271 | " segment base references" ); |
1272 | } else { |
1273 | if (wrt == NO_SEG) { |
1274 | elf_add_reloc(s, segment, addr, R_X86_64_PC64); |
1275 | addr = 0; |
1276 | } else if (wrt == elf_gotpc_sect + 1 || |
1277 | wrt == elf_got_sect + 1) { |
1278 | elf_add_gsym_reloc(s, segment, addr+size, size, |
1279 | R_X86_64_GOTPCREL64, true); |
1280 | addr = 0; |
1281 | } else if (wrt == elf_gotoff_sect + 1 || |
1282 | wrt == elf_got_sect + 1) { |
1283 | nasm_error(ERR_NONFATAL, "ELF64 requires ..gotoff references to be " |
1284 | "absolute" ); |
1285 | } else if (wrt == elf_gottpoff_sect + 1) { |
1286 | nasm_error(ERR_NONFATAL, "ELF64 requires ..gottpoff references to be " |
1287 | "dword" ); |
1288 | } else { |
1289 | nasm_error(ERR_NONFATAL, "ELF64 format does not support this" |
1290 | " use of WRT" ); |
1291 | } |
1292 | } |
1293 | elf_sect_writeaddr(s, addr, 8); |
1294 | break; |
1295 | |
1296 | default: |
1297 | panic(); |
1298 | } |
1299 | } |
1300 | |
1301 | static void elfx32_out(int32_t segto, const void *data, |
1302 | enum out_type type, uint64_t size, |
1303 | int32_t segment, int32_t wrt) |
1304 | { |
1305 | struct elf_section *s; |
1306 | int64_t addr; |
1307 | int reltype, bytes; |
1308 | int i; |
1309 | static struct symlininfo sinfo; |
1310 | |
1311 | /* |
1312 | * handle absolute-assembly (structure definitions) |
1313 | */ |
1314 | if (segto == NO_SEG) { |
1315 | if (type != OUT_RESERVE) |
1316 | nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" |
1317 | " space" ); |
1318 | return; |
1319 | } |
1320 | |
1321 | s = NULL; |
1322 | for (i = 0; i < nsects; i++) |
1323 | if (segto == sects[i]->index) { |
1324 | s = sects[i]; |
1325 | break; |
1326 | } |
1327 | if (!s) { |
1328 | int tempint; /* ignored */ |
1329 | if (segto != elf_section_names(".text" , 2, &tempint)) |
1330 | nasm_panic(0, "strange segment conditions in ELF driver" ); |
1331 | else { |
1332 | s = sects[nsects - 1]; |
1333 | i = nsects - 1; |
1334 | } |
1335 | } |
1336 | |
1337 | /* again some stabs debugging stuff */ |
1338 | sinfo.offset = s->len; |
1339 | sinfo.section = i; |
1340 | sinfo.segto = segto; |
1341 | sinfo.name = s->name; |
1342 | dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo); |
1343 | /* end of debugging stuff */ |
1344 | |
1345 | if (s->type == SHT_NOBITS && type != OUT_RESERVE) { |
1346 | nasm_error(ERR_WARNING, "attempt to initialize memory in" |
1347 | " BSS section `%s': ignored" , s->name); |
1348 | s->len += realsize(type, size); |
1349 | return; |
1350 | } |
1351 | |
1352 | switch (type) { |
1353 | case OUT_RESERVE: |
1354 | if (s->type == SHT_PROGBITS) { |
1355 | nasm_error(ERR_WARNING, "uninitialized space declared in" |
1356 | " non-BSS section `%s': zeroing" , s->name); |
1357 | elf_sect_write(s, NULL, size); |
1358 | } else |
1359 | s->len += size; |
1360 | break; |
1361 | |
1362 | case OUT_RAWDATA: |
1363 | if (segment != NO_SEG) |
1364 | nasm_panic(0, "OUT_RAWDATA with other than NO_SEG" ); |
1365 | elf_sect_write(s, data, size); |
1366 | break; |
1367 | |
1368 | case OUT_ADDRESS: |
1369 | { |
1370 | int isize = (int)size; |
1371 | int asize = abs((int)size); |
1372 | |
1373 | addr = *(int64_t *)data; |
1374 | if (segment == NO_SEG) { |
1375 | /* Do nothing */ |
1376 | } else if (segment % 2) { |
1377 | nasm_error(ERR_NONFATAL, "ELF format does not support" |
1378 | " segment base references" ); |
1379 | } else { |
1380 | if (wrt == NO_SEG) { |
1381 | switch (isize) { |
1382 | case 1: |
1383 | case -1: |
1384 | elf_add_reloc(s, segment, addr, R_X86_64_8); |
1385 | break; |
1386 | case 2: |
1387 | case -2: |
1388 | elf_add_reloc(s, segment, addr, R_X86_64_16); |
1389 | break; |
1390 | case 4: |
1391 | elf_add_reloc(s, segment, addr, R_X86_64_32); |
1392 | break; |
1393 | case -4: |
1394 | elf_add_reloc(s, segment, addr, R_X86_64_32S); |
1395 | break; |
1396 | case 8: |
1397 | case -8: |
1398 | elf_add_reloc(s, segment, addr, R_X86_64_64); |
1399 | break; |
1400 | default: |
1401 | nasm_panic(0, "internal error elfx32-hpa-871" ); |
1402 | break; |
1403 | } |
1404 | addr = 0; |
1405 | } else if (wrt == elf_gotpc_sect + 1) { |
1406 | /* |
1407 | * The user will supply GOT relative to $$. ELF |
1408 | * will let us have GOT relative to $. So we |
1409 | * need to fix up the data item by $-$$. |
1410 | */ |
1411 | addr += s->len; |
1412 | elf_add_reloc(s, segment, addr, R_X86_64_GOTPC32); |
1413 | addr = 0; |
1414 | } else if (wrt == elf_gotoff_sect + 1) { |
1415 | nasm_error(ERR_NONFATAL, "ELFX32 doesn't support " |
1416 | "R_X86_64_GOTOFF64" ); |
1417 | } else if (wrt == elf_got_sect + 1) { |
1418 | switch (asize) { |
1419 | case 4: |
1420 | elf_add_gsym_reloc(s, segment, addr, 0, |
1421 | R_X86_64_GOT32, true); |
1422 | addr = 0; |
1423 | break; |
1424 | default: |
1425 | nasm_error(ERR_NONFATAL, "invalid ..got reference" ); |
1426 | break; |
1427 | } |
1428 | } else if (wrt == elf_sym_sect + 1) { |
1429 | switch (isize) { |
1430 | case 1: |
1431 | case -1: |
1432 | elf_add_gsym_reloc(s, segment, addr, 0, |
1433 | R_X86_64_8, false); |
1434 | addr = 0; |
1435 | break; |
1436 | case 2: |
1437 | case -2: |
1438 | elf_add_gsym_reloc(s, segment, addr, 0, |
1439 | R_X86_64_16, false); |
1440 | addr = 0; |
1441 | break; |
1442 | case 4: |
1443 | elf_add_gsym_reloc(s, segment, addr, 0, |
1444 | R_X86_64_32, false); |
1445 | addr = 0; |
1446 | break; |
1447 | case -4: |
1448 | elf_add_gsym_reloc(s, segment, addr, 0, |
1449 | R_X86_64_32S, false); |
1450 | addr = 0; |
1451 | break; |
1452 | case 8: |
1453 | case -8: |
1454 | elf_add_gsym_reloc(s, segment, addr, 0, |
1455 | R_X86_64_64, false); |
1456 | addr = 0; |
1457 | break; |
1458 | default: |
1459 | nasm_panic(0, "internal error elfx32-hpa-903" ); |
1460 | break; |
1461 | } |
1462 | } else if (wrt == elf_plt_sect + 1) { |
1463 | nasm_error(ERR_NONFATAL, "ELF format cannot produce non-PC-" |
1464 | "relative PLT references" ); |
1465 | } else { |
1466 | nasm_error(ERR_NONFATAL, "ELF format does not support this" |
1467 | " use of WRT" ); |
1468 | } |
1469 | } |
1470 | elf_sect_writeaddr(s, addr, asize); |
1471 | break; |
1472 | } |
1473 | |
1474 | case OUT_REL1ADR: |
1475 | reltype = R_X86_64_PC8; |
1476 | bytes = 1; |
1477 | goto rel12adr; |
1478 | |
1479 | case OUT_REL2ADR: |
1480 | reltype = R_X86_64_PC16; |
1481 | bytes = 2; |
1482 | goto rel12adr; |
1483 | |
1484 | rel12adr: |
1485 | addr = *(int64_t *)data - size; |
1486 | if (segment == segto) |
1487 | nasm_panic(0, "intra-segment OUT_REL1ADR" ); |
1488 | if (segment == NO_SEG) { |
1489 | /* Do nothing */ |
1490 | } else if (segment % 2) { |
1491 | nasm_error(ERR_NONFATAL, "ELF format does not support" |
1492 | " segment base references" ); |
1493 | } else { |
1494 | if (wrt == NO_SEG) { |
1495 | elf_add_reloc(s, segment, addr, reltype); |
1496 | addr = 0; |
1497 | } else { |
1498 | nasm_error(ERR_NONFATAL, |
1499 | "Unsupported non-32-bit ELF relocation" ); |
1500 | } |
1501 | } |
1502 | elf_sect_writeaddr(s, addr, bytes); |
1503 | break; |
1504 | |
1505 | case OUT_REL4ADR: |
1506 | addr = *(int64_t *)data - size; |
1507 | if (segment == segto) |
1508 | nasm_panic(0, "intra-segment OUT_REL4ADR" ); |
1509 | if (segment == NO_SEG) { |
1510 | /* Do nothing */ |
1511 | } else if (segment % 2) { |
1512 | nasm_error(ERR_NONFATAL, "ELFX32 format does not support" |
1513 | " segment base references" ); |
1514 | } else { |
1515 | if (wrt == NO_SEG) { |
1516 | elf_add_reloc(s, segment, addr, R_X86_64_PC32); |
1517 | addr = 0; |
1518 | } else if (wrt == elf_plt_sect + 1) { |
1519 | elf_add_gsym_reloc(s, segment, addr+size, size, |
1520 | R_X86_64_PLT32, true); |
1521 | addr = 0; |
1522 | } else if (wrt == elf_gotpc_sect + 1 || |
1523 | wrt == elf_got_sect + 1) { |
1524 | elf_add_gsym_reloc(s, segment, addr+size, size, |
1525 | R_X86_64_GOTPCREL, true); |
1526 | addr = 0; |
1527 | } else if (wrt == elf_gotoff_sect + 1 || |
1528 | wrt == elf_got_sect + 1) { |
1529 | nasm_error(ERR_NONFATAL, "invalid ..gotoff reference" ); |
1530 | } else if (wrt == elf_gottpoff_sect + 1) { |
1531 | elf_add_gsym_reloc(s, segment, addr+size, size, |
1532 | R_X86_64_GOTTPOFF, true); |
1533 | addr = 0; |
1534 | } else { |
1535 | nasm_error(ERR_NONFATAL, "ELFX32 format does not support this" |
1536 | " use of WRT" ); |
1537 | } |
1538 | } |
1539 | elf_sect_writeaddr(s, addr, 4); |
1540 | break; |
1541 | |
1542 | case OUT_REL8ADR: |
1543 | nasm_error(ERR_NONFATAL, "32-bit ELF format does not support 64-bit relocations" ); |
1544 | addr = 0; |
1545 | elf_sect_writeaddr(s, addr, 8); |
1546 | break; |
1547 | |
1548 | default: |
1549 | panic(); |
1550 | } |
1551 | } |
1552 | |
1553 | static void elf_write(void) |
1554 | { |
1555 | int align; |
1556 | char *p; |
1557 | int i; |
1558 | |
1559 | struct SAA *symtab; |
1560 | int32_t symtablen, symtablocal; |
1561 | |
1562 | /* |
1563 | * Work out how many sections we will have. We have SHN_UNDEF, |
1564 | * then the flexible user sections, then the fixed sections |
1565 | * `.shstrtab', `.symtab' and `.strtab', then optionally |
1566 | * relocation sections for the user sections. |
1567 | */ |
1568 | nsections = sec_numspecial + 1; |
1569 | if (dfmt_is_stabs()) |
1570 | nsections += 3; |
1571 | else if (dfmt_is_dwarf()) |
1572 | nsections += 10; |
1573 | |
1574 | add_sectname("" , ".shstrtab" ); |
1575 | add_sectname("" , ".symtab" ); |
1576 | add_sectname("" , ".strtab" ); |
1577 | for (i = 0; i < nsects; i++) { |
1578 | nsections++; /* for the section itself */ |
1579 | if (sects[i]->head) { |
1580 | nsections++; /* for its relocations */ |
1581 | add_sectname(is_elf32() ? ".rel" : ".rela" , sects[i]->name); |
1582 | } |
1583 | } |
1584 | |
1585 | if (dfmt_is_stabs()) { |
1586 | /* in case the debug information is wanted, just add these three sections... */ |
1587 | add_sectname("" , ".stab" ); |
1588 | add_sectname("" , ".stabstr" ); |
1589 | add_sectname(is_elf32() ? ".rel" : ".rela" , ".stab" ); |
1590 | } else if (dfmt_is_dwarf()) { |
1591 | /* the dwarf debug standard specifies the following ten sections, |
1592 | not all of which are currently implemented, |
1593 | although all of them are defined. */ |
1594 | #define debug_aranges (int64_t) (nsections-10) |
1595 | #define debug_info (int64_t) (nsections-7) |
1596 | #define debug_abbrev (int64_t) (nsections-5) |
1597 | #define debug_line (int64_t) (nsections-4) |
1598 | add_sectname("" , ".debug_aranges" ); |
1599 | add_sectname(".rela" , ".debug_aranges" ); |
1600 | add_sectname("" , ".debug_pubnames" ); |
1601 | add_sectname("" , ".debug_info" ); |
1602 | add_sectname(".rela" , ".debug_info" ); |
1603 | add_sectname("" , ".debug_abbrev" ); |
1604 | add_sectname("" , ".debug_line" ); |
1605 | add_sectname(".rela" , ".debug_line" ); |
1606 | add_sectname("" , ".debug_frame" ); |
1607 | add_sectname("" , ".debug_loc" ); |
1608 | } |
1609 | |
1610 | /* |
1611 | * Output the ELF header. |
1612 | */ |
1613 | if (is_elf32() || is_elfx32()) { |
1614 | Elf32_Ehdr ehdr; |
1615 | |
1616 | nasm_zero(ehdr.e_ident); |
1617 | memcpy(ehdr.e_ident, ELFMAG, SELFMAG); |
1618 | ehdr.e_ident[EI_CLASS] = ELFCLASS32; |
1619 | ehdr.e_ident[EI_DATA] = ELFDATA2LSB; |
1620 | ehdr.e_ident[EI_VERSION] = EV_CURRENT; |
1621 | ehdr.e_ident[EI_OSABI] = elf_osabi; |
1622 | ehdr.e_ident[EI_ABIVERSION] = elf_abiver; |
1623 | |
1624 | ehdr.e_type = cpu_to_le16(ET_REL); |
1625 | ehdr.e_machine = cpu_to_le16(is_elf32() ? EM_386 : EM_X86_64); |
1626 | ehdr.e_version = cpu_to_le16(EV_CURRENT); |
1627 | ehdr.e_entry = 0; |
1628 | ehdr.e_phoff = 0; |
1629 | ehdr.e_shoff = sizeof(Elf64_Ehdr); |
1630 | ehdr.e_flags = 0; |
1631 | ehdr.e_ehsize = cpu_to_le16(sizeof(Elf32_Ehdr)); |
1632 | ehdr.e_phentsize = 0; |
1633 | ehdr.e_phnum = 0; |
1634 | ehdr.e_shentsize = cpu_to_le16(sizeof(Elf32_Shdr)); |
1635 | ehdr.e_shnum = cpu_to_le16(nsections); |
1636 | ehdr.e_shstrndx = cpu_to_le16(sec_shstrtab); |
1637 | |
1638 | nasm_write(&ehdr, sizeof(ehdr), ofile); |
1639 | fwritezero(sizeof(Elf64_Ehdr) - sizeof(Elf32_Ehdr), ofile); |
1640 | } else { |
1641 | Elf64_Ehdr ehdr; |
1642 | |
1643 | nasm_assert(is_elf64()); |
1644 | |
1645 | nasm_zero(ehdr.e_ident); |
1646 | memcpy(ehdr.e_ident, ELFMAG, SELFMAG); |
1647 | ehdr.e_ident[EI_CLASS] = ELFCLASS64; |
1648 | ehdr.e_ident[EI_DATA] = ELFDATA2LSB; |
1649 | ehdr.e_ident[EI_VERSION] = EV_CURRENT; |
1650 | ehdr.e_ident[EI_OSABI] = elf_osabi; |
1651 | ehdr.e_ident[EI_ABIVERSION] = elf_abiver; |
1652 | |
1653 | ehdr.e_type = cpu_to_le16(ET_REL); |
1654 | ehdr.e_machine = cpu_to_le16(EM_X86_64); |
1655 | ehdr.e_version = cpu_to_le16(EV_CURRENT); |
1656 | ehdr.e_entry = 0; |
1657 | ehdr.e_phoff = 0; |
1658 | ehdr.e_shoff = sizeof(Elf64_Ehdr); |
1659 | ehdr.e_flags = 0; |
1660 | ehdr.e_ehsize = cpu_to_le16(sizeof(Elf64_Ehdr)); |
1661 | ehdr.e_phentsize = 0; |
1662 | ehdr.e_phnum = 0; |
1663 | ehdr.e_shentsize = cpu_to_le16(sizeof(Elf64_Shdr)); |
1664 | ehdr.e_shnum = cpu_to_le16(nsections); |
1665 | ehdr.e_shstrndx = cpu_to_le16(sec_shstrtab); |
1666 | |
1667 | nasm_write(&ehdr, sizeof(ehdr), ofile); |
1668 | } |
1669 | |
1670 | /* |
1671 | * Build the symbol table and relocation tables. |
1672 | */ |
1673 | symtab = elf_build_symtab(&symtablen, &symtablocal); |
1674 | for (i = 0; i < nsects; i++) |
1675 | if (sects[i]->head) |
1676 | sects[i]->rel = elf_build_reltab(§s[i]->rellen, |
1677 | sects[i]->head); |
1678 | |
1679 | /* |
1680 | * Now output the section header table. |
1681 | */ |
1682 | |
1683 | elf_foffs = sizeof(Elf64_Ehdr) + (is_elf64() ? sizeof(Elf64_Shdr): sizeof(Elf32_Shdr)) * nsections; |
1684 | align = ALIGN(elf_foffs, SEC_FILEALIGN) - elf_foffs; |
1685 | elf_foffs += align; |
1686 | elf_nsect = 0; |
1687 | elf_sects = nasm_malloc(sizeof(*elf_sects) * nsections); |
1688 | |
1689 | /* SHN_UNDEF */ |
1690 | elf_section_header(0, SHT_NULL, 0, NULL, false, 0, SHN_UNDEF, 0, 0, 0); |
1691 | p = shstrtab + 1; |
1692 | |
1693 | /* The normal sections */ |
1694 | for (i = 0; i < nsects; i++) { |
1695 | elf_section_header(p - shstrtab, sects[i]->type, sects[i]->flags, |
1696 | (sects[i]->type == SHT_PROGBITS ? |
1697 | sects[i]->data : NULL), true, |
1698 | sects[i]->len, 0, 0, sects[i]->align, 0); |
1699 | p += strlen(p) + 1; |
1700 | } |
1701 | |
1702 | /* .shstrtab */ |
1703 | elf_section_header(p - shstrtab, SHT_STRTAB, 0, shstrtab, false, |
1704 | shstrtablen, 0, 0, 1, 0); |
1705 | p += strlen(p) + 1; |
1706 | |
1707 | /* .symtab */ |
1708 | if (is_elf64()) |
1709 | elf_section_header(p - shstrtab, SHT_SYMTAB, 0, symtab, true, |
1710 | symtablen, sec_strtab, symtablocal, 8, 24); |
1711 | else |
1712 | elf_section_header(p - shstrtab, SHT_SYMTAB, 0, symtab, true, |
1713 | symtablen, sec_strtab, symtablocal, 4, 16); |
1714 | p += strlen(p) + 1; |
1715 | |
1716 | /* .strtab */ |
1717 | elf_section_header(p - shstrtab, SHT_STRTAB, 0, strs, true, |
1718 | strslen, 0, 0, 1, 0); |
1719 | p += strlen(p) + 1; |
1720 | |
1721 | /* The relocation sections */ |
1722 | if (is_elf32()) { |
1723 | for (i = 0; i < nsects; i++) { |
1724 | if (sects[i]->head) { |
1725 | elf_section_header(p - shstrtab, SHT_REL, 0, sects[i]->rel, true, |
1726 | sects[i]->rellen, sec_symtab, i + 1, 4, 8); |
1727 | p += strlen(p) + 1; |
1728 | } |
1729 | } |
1730 | } else if (is_elfx32()) { |
1731 | for (i = 0; i < nsects; i++) { |
1732 | if (sects[i]->head) { |
1733 | elf_section_header(p - shstrtab, SHT_RELA, 0, sects[i]->rel, true, |
1734 | sects[i]->rellen, sec_symtab, i + 1, 4, 12); |
1735 | p += strlen(p) + 1; |
1736 | } |
1737 | } |
1738 | } else { |
1739 | nasm_assert(is_elf64()); |
1740 | for (i = 0; i < nsects; i++) { |
1741 | if (sects[i]->head) { |
1742 | elf_section_header(p - shstrtab, SHT_RELA, 0, sects[i]->rel, true, |
1743 | sects[i]->rellen, sec_symtab, i + 1, 8, 24); |
1744 | p += strlen(p) + 1; |
1745 | } |
1746 | } |
1747 | } |
1748 | |
1749 | if (dfmt_is_stabs()) { |
1750 | /* for debugging information, create the last three sections |
1751 | which are the .stab , .stabstr and .rel.stab sections respectively */ |
1752 | |
1753 | /* this function call creates the stab sections in memory */ |
1754 | stabs_generate(); |
1755 | |
1756 | if (stabbuf && stabstrbuf && stabrelbuf) { |
1757 | elf_section_header(p - shstrtab, SHT_PROGBITS, 0, stabbuf, false, |
1758 | stablen, sec_stabstr, 0, 4, 12); |
1759 | p += strlen(p) + 1; |
1760 | |
1761 | elf_section_header(p - shstrtab, SHT_STRTAB, 0, stabstrbuf, false, |
1762 | stabstrlen, 0, 0, 4, 0); |
1763 | p += strlen(p) + 1; |
1764 | |
1765 | /* link -> symtable info -> section to refer to */ |
1766 | if (is_elf32()) { |
1767 | elf_section_header(p - shstrtab, SHT_REL, 0, stabrelbuf, false, |
1768 | stabrellen, sec_symtab, sec_stab, 4, 8); |
1769 | } else { |
1770 | elf_section_header(p - shstrtab, SHT_RELA, 0, stabrelbuf, false, |
1771 | stabrellen, sec_symtab, sec_stab, 4, is_elf64() ? 24 : 12); |
1772 | } |
1773 | p += strlen(p) + 1; |
1774 | } |
1775 | } else if (dfmt_is_dwarf()) { |
1776 | /* for dwarf debugging information, create the ten dwarf sections */ |
1777 | |
1778 | /* this function call creates the dwarf sections in memory */ |
1779 | if (dwarf_fsect) |
1780 | dwarf_generate(); |
1781 | |
1782 | elf_section_header(p - shstrtab, SHT_PROGBITS, 0, arangesbuf, false, |
1783 | arangeslen, 0, 0, 1, 0); |
1784 | p += strlen(p) + 1; |
1785 | |
1786 | elf_section_header(p - shstrtab, SHT_RELA, 0, arangesrelbuf, false, |
1787 | arangesrellen, sec_symtab, |
1788 | is_elf64() ? debug_aranges : sec_debug_aranges, |
1789 | 1, is_elf64() ? 24 : 12); |
1790 | p += strlen(p) + 1; |
1791 | |
1792 | elf_section_header(p - shstrtab, SHT_PROGBITS, 0, pubnamesbuf, |
1793 | false, pubnameslen, 0, 0, 1, 0); |
1794 | p += strlen(p) + 1; |
1795 | |
1796 | elf_section_header(p - shstrtab, SHT_PROGBITS, 0, infobuf, false, |
1797 | infolen, 0, 0, 1, 0); |
1798 | p += strlen(p) + 1; |
1799 | |
1800 | elf_section_header(p - shstrtab, SHT_RELA, 0, inforelbuf, false, |
1801 | inforellen, sec_symtab, |
1802 | is_elf64() ? debug_info : sec_debug_info, |
1803 | 1, is_elf64() ? 24 : 12); |
1804 | p += strlen(p) + 1; |
1805 | |
1806 | elf_section_header(p - shstrtab, SHT_PROGBITS, 0, abbrevbuf, false, |
1807 | abbrevlen, 0, 0, 1, 0); |
1808 | p += strlen(p) + 1; |
1809 | |
1810 | elf_section_header(p - shstrtab, SHT_PROGBITS, 0, linebuf, false, |
1811 | linelen, 0, 0, 1, 0); |
1812 | p += strlen(p) + 1; |
1813 | |
1814 | elf_section_header(p - shstrtab, SHT_RELA, 0, linerelbuf, false, |
1815 | linerellen, sec_symtab, |
1816 | is_elf64() ? debug_line : sec_debug_line, |
1817 | 1, is_elf64() ? 24 : 12); |
1818 | p += strlen(p) + 1; |
1819 | |
1820 | elf_section_header(p - shstrtab, SHT_PROGBITS, 0, framebuf, false, |
1821 | framelen, 0, 0, 8, 0); |
1822 | p += strlen(p) + 1; |
1823 | |
1824 | elf_section_header(p - shstrtab, SHT_PROGBITS, 0, locbuf, false, |
1825 | loclen, 0, 0, 1, 0); |
1826 | p += strlen(p) + 1; |
1827 | } |
1828 | fwritezero(align, ofile); |
1829 | |
1830 | /* |
1831 | * Now output the sections. |
1832 | */ |
1833 | elf_write_sections(); |
1834 | |
1835 | nasm_free(elf_sects); |
1836 | saa_free(symtab); |
1837 | } |
1838 | |
1839 | static struct SAA *elf_build_symtab(int32_t *len, int32_t *local) |
1840 | { |
1841 | struct SAA *s = saa_init(1L); |
1842 | struct elf_symbol *sym; |
1843 | int i; |
1844 | |
1845 | size_t usize = is_elf64() ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym); |
1846 | union { |
1847 | Elf32_Sym sym32; |
1848 | Elf64_Sym sym64; |
1849 | } u; |
1850 | |
1851 | *len = *local = 0; |
1852 | |
1853 | /* |
1854 | * Zero symbol first as required by spec. |
1855 | */ |
1856 | saa_wbytes(s, NULL, usize); |
1857 | *len += usize; |
1858 | (*local)++; |
1859 | |
1860 | /* |
1861 | * Next, an entry for the file name. |
1862 | */ |
1863 | if (is_elf64()) { |
1864 | u.sym64.st_name = cpu_to_le32(1); |
1865 | u.sym64.st_info = ELF64_ST_INFO(STB_LOCAL, STT_FILE); |
1866 | u.sym64.st_other = 0; |
1867 | u.sym64.st_shndx = cpu_to_le16(SHN_ABS); |
1868 | u.sym64.st_value = 0; |
1869 | u.sym64.st_size = 0; |
1870 | } else { |
1871 | u.sym32.st_name = cpu_to_le32(1); |
1872 | u.sym32.st_value = 0; |
1873 | u.sym32.st_size = 0; |
1874 | u.sym32.st_info = ELF32_ST_INFO(STB_LOCAL, STT_FILE); |
1875 | u.sym32.st_other = 0; |
1876 | u.sym32.st_shndx = cpu_to_le16(SHN_ABS); |
1877 | } |
1878 | saa_wbytes(s, &u, usize); |
1879 | *len += usize; |
1880 | (*local)++; |
1881 | |
1882 | |
1883 | /* |
1884 | * Now some standard symbols defining the segments, for relocation |
1885 | * purposes. |
1886 | */ |
1887 | if (is_elf64()) { |
1888 | u.sym64.st_name = 0; |
1889 | u.sym64.st_other = 0; |
1890 | u.sym64.st_value = 0; |
1891 | u.sym64.st_size = 0; |
1892 | for (i = 1; i <= nsects; i++) { |
1893 | u.sym64.st_info = ELF64_ST_INFO(STB_LOCAL, STT_SECTION); |
1894 | u.sym64.st_shndx = cpu_to_le16(i); |
1895 | saa_wbytes(s, &u, usize); |
1896 | *len += usize; |
1897 | (*local)++; |
1898 | } |
1899 | } else { |
1900 | u.sym32.st_name = 0; |
1901 | u.sym32.st_value = 0; |
1902 | u.sym32.st_size = 0; |
1903 | u.sym32.st_other = 0; |
1904 | for (i = 1; i <= nsects; i++) { |
1905 | u.sym32.st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION); |
1906 | u.sym32.st_shndx = cpu_to_le16(i); |
1907 | saa_wbytes(s, &u, usize); |
1908 | *len += usize; |
1909 | (*local)++; |
1910 | } |
1911 | } |
1912 | |
1913 | /* |
1914 | * Now the other local symbols. |
1915 | */ |
1916 | saa_rewind(syms); |
1917 | if (is_elf64()) { |
1918 | while ((sym = saa_rstruct(syms))) { |
1919 | if (sym->type & SYM_GLOBAL) |
1920 | continue; |
1921 | u.sym64.st_name = cpu_to_le32(sym->strpos); |
1922 | u.sym64.st_info = sym->type; |
1923 | u.sym64.st_other = sym->other; |
1924 | u.sym64.st_shndx = cpu_to_le16(sym->section); |
1925 | u.sym64.st_value = cpu_to_le64(sym->symv.key); |
1926 | u.sym64.st_size = cpu_to_le64(sym->size); |
1927 | saa_wbytes(s, &u, usize); |
1928 | *len += usize; |
1929 | (*local)++; |
1930 | } |
1931 | /* |
1932 | * dwarf needs symbols for debug sections |
1933 | * which are relocation targets. |
1934 | */ |
1935 | if (dfmt_is_dwarf()) { |
1936 | dwarf_infosym = *local; |
1937 | u.sym64.st_name = 0; |
1938 | u.sym64.st_info = ELF64_ST_INFO(STB_LOCAL, STT_SECTION); |
1939 | u.sym64.st_other = 0; |
1940 | u.sym64.st_shndx = cpu_to_le16(debug_info); |
1941 | u.sym64.st_value = 0; |
1942 | u.sym64.st_size = 0; |
1943 | saa_wbytes(s, &u, usize); |
1944 | *len += usize; |
1945 | (*local)++; |
1946 | dwarf_abbrevsym = *local; |
1947 | u.sym64.st_name = 0; |
1948 | u.sym64.st_info = ELF64_ST_INFO(STB_LOCAL, STT_SECTION); |
1949 | u.sym64.st_other = 0; |
1950 | u.sym64.st_shndx = cpu_to_le16(debug_abbrev); |
1951 | u.sym64.st_value = 0; |
1952 | u.sym64.st_size = 0; |
1953 | saa_wbytes(s, &u, usize); |
1954 | *len += usize; |
1955 | (*local)++; |
1956 | dwarf_linesym = *local; |
1957 | u.sym64.st_name = 0; |
1958 | u.sym64.st_info = ELF64_ST_INFO(STB_LOCAL, STT_SECTION); |
1959 | u.sym64.st_other = 0; |
1960 | u.sym64.st_shndx = cpu_to_le16(debug_line); |
1961 | u.sym64.st_value = 0; |
1962 | u.sym64.st_size = 0; |
1963 | saa_wbytes(s, &u, usize); |
1964 | *len += usize; |
1965 | (*local)++; |
1966 | } |
1967 | } else { |
1968 | while ((sym = saa_rstruct(syms))) { |
1969 | if (sym->type & SYM_GLOBAL) |
1970 | continue; |
1971 | u.sym32.st_name = cpu_to_le32(sym->strpos); |
1972 | u.sym32.st_value = cpu_to_le32(sym->symv.key); |
1973 | u.sym32.st_size = cpu_to_le32(sym->size); |
1974 | u.sym32.st_info = sym->type; |
1975 | u.sym32.st_other = sym->other; |
1976 | u.sym32.st_shndx = cpu_to_le16(sym->section); |
1977 | saa_wbytes(s, &u, usize); |
1978 | *len += usize; |
1979 | (*local)++; |
1980 | } |
1981 | /* |
1982 | * dwarf needs symbols for debug sections |
1983 | * which are relocation targets. |
1984 | */ |
1985 | if (dfmt_is_dwarf()) { |
1986 | dwarf_infosym = *local; |
1987 | u.sym32.st_name = 0; |
1988 | u.sym32.st_value = 0; |
1989 | u.sym32.st_size = 0; |
1990 | u.sym32.st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION); |
1991 | u.sym32.st_other = 0; |
1992 | u.sym32.st_shndx = cpu_to_le16(sec_debug_info); |
1993 | saa_wbytes(s, &u, usize); |
1994 | *len += usize; |
1995 | (*local)++; |
1996 | dwarf_abbrevsym = *local; |
1997 | u.sym32.st_name = 0; |
1998 | u.sym32.st_value = 0; |
1999 | u.sym32.st_size = 0; |
2000 | u.sym32.st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION); |
2001 | u.sym32.st_other = 0; |
2002 | u.sym32.st_shndx = cpu_to_le16(sec_debug_abbrev); |
2003 | saa_wbytes(s, &u, usize); |
2004 | *len += usize; |
2005 | (*local)++; |
2006 | dwarf_linesym = *local; |
2007 | u.sym32.st_name = 0; |
2008 | u.sym32.st_value = 0; |
2009 | u.sym32.st_size = 0; |
2010 | u.sym32.st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION); |
2011 | u.sym32.st_other = 0; |
2012 | u.sym32.st_shndx = cpu_to_le16(sec_debug_line); |
2013 | saa_wbytes(s, &u, usize); |
2014 | *len += usize; |
2015 | (*local)++; |
2016 | } |
2017 | } |
2018 | |
2019 | /* |
2020 | * Now the global symbols. |
2021 | */ |
2022 | saa_rewind(syms); |
2023 | if (is_elf64()) { |
2024 | while ((sym = saa_rstruct(syms))) { |
2025 | if (!(sym->type & SYM_GLOBAL)) |
2026 | continue; |
2027 | u.sym64.st_name = cpu_to_le32(sym->strpos); |
2028 | u.sym64.st_info = sym->type; |
2029 | u.sym64.st_other = sym->other; |
2030 | u.sym64.st_shndx = cpu_to_le16(sym->section); |
2031 | u.sym64.st_value = cpu_to_le64(sym->symv.key); |
2032 | u.sym64.st_size = cpu_to_le64(sym->size); |
2033 | saa_wbytes(s, &u, usize); |
2034 | *len += usize; |
2035 | } |
2036 | } else { |
2037 | while ((sym = saa_rstruct(syms))) { |
2038 | if (!(sym->type & SYM_GLOBAL)) |
2039 | continue; |
2040 | u.sym32.st_name = cpu_to_le32(sym->strpos); |
2041 | u.sym32.st_value = cpu_to_le32(sym->symv.key); |
2042 | u.sym32.st_size = cpu_to_le32(sym->size); |
2043 | u.sym32.st_info = sym->type; |
2044 | u.sym32.st_other = sym->other; |
2045 | u.sym32.st_shndx = cpu_to_le16(sym->section); |
2046 | saa_wbytes(s, &u, usize); |
2047 | *len += usize; |
2048 | } |
2049 | } |
2050 | |
2051 | return s; |
2052 | } |
2053 | |
2054 | static struct SAA *elf_build_reltab(uint64_t *len, struct elf_reloc *r) |
2055 | { |
2056 | struct SAA *s; |
2057 | int32_t global_offset; |
2058 | |
2059 | size_t usize = is_elf64() ? sizeof(Elf64_Rela) : |
2060 | (is_elfx32() ? sizeof(Elf32_Rela) : sizeof(Elf32_Rel)); |
2061 | union { |
2062 | Elf32_Rel rel32; |
2063 | Elf32_Rela rela32; |
2064 | Elf64_Rela rela64; |
2065 | } u; |
2066 | |
2067 | if (!r) |
2068 | return NULL; |
2069 | |
2070 | s = saa_init(1L); |
2071 | *len = 0; |
2072 | |
2073 | /* |
2074 | * How to onvert from a global placeholder to a real symbol index; |
2075 | * the +2 refers to the two special entries, the null entry and |
2076 | * the filename entry. |
2077 | */ |
2078 | global_offset = -GLOBAL_TEMP_BASE + nsects + nlocals + ndebugs + 2; |
2079 | |
2080 | if (is_elf32()) { |
2081 | while (r) { |
2082 | int32_t sym = r->symbol; |
2083 | |
2084 | if (sym >= GLOBAL_TEMP_BASE) |
2085 | sym += global_offset; |
2086 | |
2087 | u.rel32.r_offset = cpu_to_le32(r->address); |
2088 | u.rel32.r_info = cpu_to_le32(ELF32_R_INFO(sym, r->type)); |
2089 | saa_wbytes(s, &u, usize); |
2090 | *len += usize; |
2091 | |
2092 | r = r->next; |
2093 | } |
2094 | } else if (is_elfx32()) { |
2095 | while (r) { |
2096 | int32_t sym = r->symbol; |
2097 | |
2098 | if (sym >= GLOBAL_TEMP_BASE) |
2099 | sym += global_offset; |
2100 | |
2101 | u.rela32.r_offset = cpu_to_le32(r->address); |
2102 | u.rela32.r_info = cpu_to_le32(ELF32_R_INFO(sym, r->type)); |
2103 | u.rela32.r_addend = cpu_to_le32(r->offset); |
2104 | saa_wbytes(s, &u, usize); |
2105 | *len += usize; |
2106 | |
2107 | r = r->next; |
2108 | } |
2109 | } else { |
2110 | nasm_assert(is_elf64()); |
2111 | while (r) { |
2112 | int32_t sym = r->symbol; |
2113 | |
2114 | if (sym >= GLOBAL_TEMP_BASE) |
2115 | sym += global_offset; |
2116 | |
2117 | u.rela64.r_offset = cpu_to_le64(r->address); |
2118 | u.rela64.r_info = cpu_to_le64(ELF64_R_INFO(sym, r->type)); |
2119 | u.rela64.r_addend = cpu_to_le64(r->offset); |
2120 | saa_wbytes(s, &u, usize); |
2121 | *len += usize; |
2122 | |
2123 | r = r->next; |
2124 | } |
2125 | } |
2126 | |
2127 | return s; |
2128 | } |
2129 | |
2130 | static void (int name, int type, uint64_t flags, |
2131 | void *data, bool is_saa, uint64_t datalen, |
2132 | int link, int info, int align, int eltsize) |
2133 | { |
2134 | union { |
2135 | Elf32_Shdr shdr32; |
2136 | Elf64_Shdr shdr64; |
2137 | } shdr; |
2138 | |
2139 | elf_sects[elf_nsect].data = data; |
2140 | elf_sects[elf_nsect].len = datalen; |
2141 | elf_sects[elf_nsect].is_saa = is_saa; |
2142 | elf_nsect++; |
2143 | |
2144 | if (is_elf32() || is_elfx32()) { |
2145 | shdr.shdr32.sh_name = cpu_to_le32(name); |
2146 | shdr.shdr32.sh_type = cpu_to_le32(type); |
2147 | shdr.shdr32.sh_flags = cpu_to_le32(flags); |
2148 | shdr.shdr32.sh_addr = 0; |
2149 | shdr.shdr32.sh_offset = cpu_to_le32(type == SHT_NULL ? 0 : elf_foffs); |
2150 | shdr.shdr32.sh_size = cpu_to_le32(datalen); |
2151 | if (data) |
2152 | elf_foffs += ALIGN(datalen, SEC_FILEALIGN); |
2153 | shdr.shdr32.sh_link = cpu_to_le32(link); |
2154 | shdr.shdr32.sh_info = cpu_to_le32(info); |
2155 | shdr.shdr32.sh_addralign = cpu_to_le32(align); |
2156 | shdr.shdr32.sh_entsize = cpu_to_le32(eltsize); |
2157 | } else { |
2158 | nasm_assert(is_elf64()); |
2159 | |
2160 | shdr.shdr64.sh_name = cpu_to_le32(name); |
2161 | shdr.shdr64.sh_type = cpu_to_le32(type); |
2162 | shdr.shdr64.sh_flags = cpu_to_le64(flags); |
2163 | shdr.shdr64.sh_addr = 0; |
2164 | shdr.shdr64.sh_offset = cpu_to_le64(type == SHT_NULL ? 0 : elf_foffs); |
2165 | shdr.shdr64.sh_size = cpu_to_le32(datalen); |
2166 | if (data) |
2167 | elf_foffs += ALIGN(datalen, SEC_FILEALIGN); |
2168 | shdr.shdr64.sh_link = cpu_to_le32(link); |
2169 | shdr.shdr64.sh_info = cpu_to_le32(info); |
2170 | shdr.shdr64.sh_addralign = cpu_to_le64(align); |
2171 | shdr.shdr64.sh_entsize = cpu_to_le64(eltsize); |
2172 | } |
2173 | |
2174 | nasm_write(&shdr, is_elf64() ? sizeof(shdr.shdr64) : sizeof(shdr.shdr32), ofile); |
2175 | } |
2176 | |
2177 | static void elf_write_sections(void) |
2178 | { |
2179 | int i; |
2180 | for (i = 0; i < elf_nsect; i++) |
2181 | if (elf_sects[i].data) { |
2182 | int32_t len = elf_sects[i].len; |
2183 | int32_t reallen = ALIGN(len, SEC_FILEALIGN); |
2184 | int32_t align = reallen - len; |
2185 | if (elf_sects[i].is_saa) |
2186 | saa_fpwrite(elf_sects[i].data, ofile); |
2187 | else |
2188 | nasm_write(elf_sects[i].data, len, ofile); |
2189 | fwritezero(align, ofile); |
2190 | } |
2191 | } |
2192 | |
2193 | static void elf_sect_write(struct elf_section *sect, const void *data, size_t len) |
2194 | { |
2195 | saa_wbytes(sect->data, data, len); |
2196 | sect->len += len; |
2197 | } |
2198 | |
2199 | static void elf_sect_writeaddr(struct elf_section *sect, int64_t data, size_t len) |
2200 | { |
2201 | saa_writeaddr(sect->data, data, len); |
2202 | sect->len += len; |
2203 | } |
2204 | |
2205 | static void elf_sectalign(int32_t seg, unsigned int value) |
2206 | { |
2207 | struct elf_section *s = NULL; |
2208 | int i; |
2209 | |
2210 | for (i = 0; i < nsects; i++) { |
2211 | if (sects[i]->index == seg) { |
2212 | s = sects[i]; |
2213 | break; |
2214 | } |
2215 | } |
2216 | if (!s || !is_power2(value)) |
2217 | return; |
2218 | |
2219 | if (value > s->align) |
2220 | s->align = value; |
2221 | } |
2222 | |
2223 | static int32_t elf_segbase(int32_t segment) |
2224 | { |
2225 | return segment; |
2226 | } |
2227 | |
2228 | extern macros_t elf_stdmac[]; |
2229 | |
2230 | /* Claim "elf" as a pragma namespace, for the future */ |
2231 | static const struct pragma_facility elf_pragma_list[] = |
2232 | { |
2233 | { "elf" , NULL }, |
2234 | { NULL, NULL } /* Implements the canonical output name */ |
2235 | }; |
2236 | |
2237 | |
2238 | static const struct dfmt elf32_df_dwarf = { |
2239 | "ELF32 (i386) dwarf debug format for Linux/Unix" , |
2240 | "dwarf" , |
2241 | dwarf_init, |
2242 | dwarf_linenum, |
2243 | null_debug_deflabel, |
2244 | null_debug_directive, |
2245 | debug_typevalue, |
2246 | dwarf_output, |
2247 | dwarf_cleanup, |
2248 | NULL /* pragma list */ |
2249 | }; |
2250 | |
2251 | static const struct dfmt elf32_df_stabs = { |
2252 | "ELF32 (i386) stabs debug format for Linux/Unix" , |
2253 | "stabs" , |
2254 | null_debug_init, |
2255 | stabs_linenum, |
2256 | null_debug_deflabel, |
2257 | null_debug_directive, |
2258 | debug_typevalue, |
2259 | stabs_output, |
2260 | stabs_cleanup, |
2261 | NULL /* pragma list */ |
2262 | }; |
2263 | |
2264 | static const struct dfmt * const elf32_debugs_arr[3] = |
2265 | { &elf32_df_dwarf, &elf32_df_stabs, NULL }; |
2266 | |
2267 | const struct ofmt of_elf32 = { |
2268 | "ELF32 (i386) object files (e.g. Linux)" , |
2269 | "elf32" , |
2270 | ".o" , |
2271 | 0, |
2272 | 32, |
2273 | elf32_debugs_arr, |
2274 | &elf32_df_stabs, |
2275 | elf_stdmac, |
2276 | elf_init, |
2277 | null_reset, |
2278 | nasm_do_legacy_output, |
2279 | elf32_out, |
2280 | elf_deflabel, |
2281 | elf_section_names, |
2282 | NULL, |
2283 | elf_sectalign, |
2284 | elf_segbase, |
2285 | elf_directive, |
2286 | elf_cleanup, |
2287 | elf_pragma_list, |
2288 | }; |
2289 | |
2290 | static const struct dfmt elf64_df_dwarf = { |
2291 | "ELF64 (x86-64) dwarf debug format for Linux/Unix" , |
2292 | "dwarf" , |
2293 | dwarf_init, |
2294 | dwarf_linenum, |
2295 | null_debug_deflabel, |
2296 | null_debug_directive, |
2297 | debug_typevalue, |
2298 | dwarf_output, |
2299 | dwarf_cleanup, |
2300 | NULL /* pragma list */ |
2301 | }; |
2302 | |
2303 | static const struct dfmt elf64_df_stabs = { |
2304 | "ELF64 (x86-64) stabs debug format for Linux/Unix" , |
2305 | "stabs" , |
2306 | null_debug_init, |
2307 | stabs_linenum, |
2308 | null_debug_deflabel, |
2309 | null_debug_directive, |
2310 | debug_typevalue, |
2311 | stabs_output, |
2312 | stabs_cleanup, |
2313 | NULL /* pragma list */ |
2314 | }; |
2315 | |
2316 | static const struct dfmt * const elf64_debugs_arr[3] = |
2317 | { &elf64_df_dwarf, &elf64_df_stabs, NULL }; |
2318 | |
2319 | const struct ofmt of_elf64 = { |
2320 | "ELF64 (x86_64) object files (e.g. Linux)" , |
2321 | "elf64" , |
2322 | ".o" , |
2323 | 0, |
2324 | 64, |
2325 | elf64_debugs_arr, |
2326 | &elf64_df_stabs, |
2327 | elf_stdmac, |
2328 | elf_init, |
2329 | null_reset, |
2330 | nasm_do_legacy_output, |
2331 | elf64_out, |
2332 | elf_deflabel, |
2333 | elf_section_names, |
2334 | NULL, |
2335 | elf_sectalign, |
2336 | elf_segbase, |
2337 | elf_directive, |
2338 | elf_cleanup, |
2339 | elf_pragma_list, |
2340 | }; |
2341 | |
2342 | static const struct dfmt elfx32_df_dwarf = { |
2343 | "ELFX32 (x86-64) dwarf debug format for Linux/Unix" , |
2344 | "dwarf" , |
2345 | dwarf_init, |
2346 | dwarf_linenum, |
2347 | null_debug_deflabel, |
2348 | null_debug_directive, |
2349 | debug_typevalue, |
2350 | dwarf_output, |
2351 | dwarf_cleanup, |
2352 | NULL /* pragma list */ |
2353 | }; |
2354 | |
2355 | static const struct dfmt elfx32_df_stabs = { |
2356 | "ELFX32 (x86-64) stabs debug format for Linux/Unix" , |
2357 | "stabs" , |
2358 | null_debug_init, |
2359 | stabs_linenum, |
2360 | null_debug_deflabel, |
2361 | null_debug_directive, |
2362 | debug_typevalue, |
2363 | stabs_output, |
2364 | stabs_cleanup, |
2365 | elf_pragma_list, |
2366 | }; |
2367 | |
2368 | static const struct dfmt * const elfx32_debugs_arr[3] = |
2369 | { &elfx32_df_dwarf, &elfx32_df_stabs, NULL }; |
2370 | |
2371 | const struct ofmt of_elfx32 = { |
2372 | "ELFX32 (x86_64) object files (e.g. Linux)" , |
2373 | "elfx32" , |
2374 | ".o" , |
2375 | 0, |
2376 | 64, |
2377 | elfx32_debugs_arr, |
2378 | &elfx32_df_stabs, |
2379 | elf_stdmac, |
2380 | elf_init, |
2381 | null_reset, |
2382 | nasm_do_legacy_output, |
2383 | elfx32_out, |
2384 | elf_deflabel, |
2385 | elf_section_names, |
2386 | NULL, |
2387 | elf_sectalign, |
2388 | elf_segbase, |
2389 | elf_directive, |
2390 | elf_cleanup, |
2391 | NULL /* pragma list */ |
2392 | }; |
2393 | |
2394 | static bool is_elf64(void) |
2395 | { |
2396 | return ofmt == &of_elf64; |
2397 | } |
2398 | |
2399 | static bool is_elf32(void) |
2400 | { |
2401 | return ofmt == &of_elf32; |
2402 | } |
2403 | |
2404 | static bool is_elfx32(void) |
2405 | { |
2406 | return ofmt == &of_elfx32; |
2407 | } |
2408 | |
2409 | static bool dfmt_is_stabs(void) |
2410 | { |
2411 | return dfmt == &elf32_df_stabs || |
2412 | dfmt == &elfx32_df_stabs || |
2413 | dfmt == &elf64_df_stabs; |
2414 | } |
2415 | |
2416 | static bool dfmt_is_dwarf(void) |
2417 | { |
2418 | return dfmt == &elf32_df_dwarf || |
2419 | dfmt == &elfx32_df_dwarf || |
2420 | dfmt == &elf64_df_dwarf; |
2421 | } |
2422 | |
2423 | /* common debugging routines */ |
2424 | static void debug_typevalue(int32_t type) |
2425 | { |
2426 | int32_t stype, ssize; |
2427 | switch (TYM_TYPE(type)) { |
2428 | case TY_LABEL: |
2429 | ssize = 0; |
2430 | stype = STT_NOTYPE; |
2431 | break; |
2432 | case TY_BYTE: |
2433 | ssize = 1; |
2434 | stype = STT_OBJECT; |
2435 | break; |
2436 | case TY_WORD: |
2437 | ssize = 2; |
2438 | stype = STT_OBJECT; |
2439 | break; |
2440 | case TY_DWORD: |
2441 | ssize = 4; |
2442 | stype = STT_OBJECT; |
2443 | break; |
2444 | case TY_FLOAT: |
2445 | ssize = 4; |
2446 | stype = STT_OBJECT; |
2447 | break; |
2448 | case TY_QWORD: |
2449 | ssize = 8; |
2450 | stype = STT_OBJECT; |
2451 | break; |
2452 | case TY_TBYTE: |
2453 | ssize = 10; |
2454 | stype = STT_OBJECT; |
2455 | break; |
2456 | case TY_OWORD: |
2457 | ssize = 16; |
2458 | stype = STT_OBJECT; |
2459 | break; |
2460 | case TY_YWORD: |
2461 | ssize = 32; |
2462 | stype = STT_OBJECT; |
2463 | break; |
2464 | case TY_ZWORD: |
2465 | ssize = 64; |
2466 | stype = STT_OBJECT; |
2467 | break; |
2468 | case TY_COMMON: |
2469 | ssize = 0; |
2470 | stype = STT_COMMON; |
2471 | break; |
2472 | case TY_SEG: |
2473 | ssize = 0; |
2474 | stype = STT_SECTION; |
2475 | break; |
2476 | case TY_EXTERN: |
2477 | ssize = 0; |
2478 | stype = STT_NOTYPE; |
2479 | break; |
2480 | case TY_EQU: |
2481 | ssize = 0; |
2482 | stype = STT_NOTYPE; |
2483 | break; |
2484 | default: |
2485 | ssize = 0; |
2486 | stype = STT_NOTYPE; |
2487 | break; |
2488 | } |
2489 | if (stype == STT_OBJECT && lastsym && !lastsym->type) { |
2490 | lastsym->size = ssize; |
2491 | lastsym->type = stype; |
2492 | } |
2493 | } |
2494 | |
2495 | /* stabs debugging routines */ |
2496 | |
2497 | static void stabs_linenum(const char *filename, int32_t linenumber, int32_t segto) |
2498 | { |
2499 | (void)segto; |
2500 | if (!stabs_filename) { |
2501 | stabs_filename = nasm_malloc(strlen(filename) + 1); |
2502 | strcpy(stabs_filename, filename); |
2503 | } else { |
2504 | if (strcmp(stabs_filename, filename)) { |
2505 | /* yep, a memory leak...this program is one-shot anyway, so who cares... |
2506 | in fact, this leak comes in quite handy to maintain a list of files |
2507 | encountered so far in the symbol lines... */ |
2508 | |
2509 | /* why not nasm_free(stabs_filename); we're done with the old one */ |
2510 | |
2511 | stabs_filename = nasm_malloc(strlen(filename) + 1); |
2512 | strcpy(stabs_filename, filename); |
2513 | } |
2514 | } |
2515 | debug_immcall = 1; |
2516 | currentline = linenumber; |
2517 | } |
2518 | |
2519 | static void stabs_output(int type, void *param) |
2520 | { |
2521 | struct symlininfo *s; |
2522 | struct linelist *el; |
2523 | if (type == TY_DEBUGSYMLIN) { |
2524 | if (debug_immcall) { |
2525 | s = (struct symlininfo *)param; |
2526 | if (!(sects[s->section]->flags & SHF_EXECINSTR)) |
2527 | return; /* line info is only collected for executable sections */ |
2528 | numlinestabs++; |
2529 | el = nasm_malloc(sizeof(struct linelist)); |
2530 | el->info.offset = s->offset; |
2531 | el->info.section = s->section; |
2532 | el->info.name = s->name; |
2533 | el->line = currentline; |
2534 | el->filename = stabs_filename; |
2535 | el->next = 0; |
2536 | if (stabslines) { |
2537 | stabslines->last->next = el; |
2538 | stabslines->last = el; |
2539 | } else { |
2540 | stabslines = el; |
2541 | stabslines->last = el; |
2542 | } |
2543 | } |
2544 | } |
2545 | debug_immcall = 0; |
2546 | } |
2547 | |
2548 | /* for creating the .stab , .stabstr and .rel.stab sections in memory */ |
2549 | |
2550 | static void stabs_generate(void) |
2551 | { |
2552 | int i, numfiles, strsize, numstabs = 0, currfile, mainfileindex; |
2553 | uint8_t *sbuf, *ssbuf, *rbuf, *sptr, *rptr; |
2554 | char **allfiles; |
2555 | int *fileidx; |
2556 | |
2557 | struct linelist *ptr; |
2558 | |
2559 | ptr = stabslines; |
2560 | |
2561 | allfiles = nasm_zalloc(numlinestabs * sizeof(char *)); |
2562 | numfiles = 0; |
2563 | while (ptr) { |
2564 | if (numfiles == 0) { |
2565 | allfiles[0] = ptr->filename; |
2566 | numfiles++; |
2567 | } else { |
2568 | for (i = 0; i < numfiles; i++) { |
2569 | if (!strcmp(allfiles[i], ptr->filename)) |
2570 | break; |
2571 | } |
2572 | if (i >= numfiles) { |
2573 | allfiles[i] = ptr->filename; |
2574 | numfiles++; |
2575 | } |
2576 | } |
2577 | ptr = ptr->next; |
2578 | } |
2579 | strsize = 1; |
2580 | fileidx = nasm_malloc(numfiles * sizeof(int)); |
2581 | for (i = 0; i < numfiles; i++) { |
2582 | fileidx[i] = strsize; |
2583 | strsize += strlen(allfiles[i]) + 1; |
2584 | } |
2585 | currfile = mainfileindex = 0; |
2586 | for (i = 0; i < numfiles; i++) { |
2587 | if (!strcmp(allfiles[i], elf_module)) { |
2588 | currfile = mainfileindex = i; |
2589 | break; |
2590 | } |
2591 | } |
2592 | |
2593 | /* |
2594 | * worst case size of the stab buffer would be: |
2595 | * the sourcefiles changes each line, which would mean 1 SOL, 1 SYMLIN per line |
2596 | * plus one "ending" entry |
2597 | */ |
2598 | sbuf = nasm_malloc((numlinestabs * 2 + 4) * |
2599 | sizeof(struct stabentry)); |
2600 | ssbuf = nasm_malloc(strsize); |
2601 | rbuf = nasm_malloc(numlinestabs * (is_elf64() ? 16 : 8) * (2 + 3)); |
2602 | rptr = rbuf; |
2603 | |
2604 | for (i = 0; i < numfiles; i++) |
2605 | strcpy((char *)ssbuf + fileidx[i], allfiles[i]); |
2606 | ssbuf[0] = 0; |
2607 | |
2608 | stabstrlen = strsize; /* set global variable for length of stab strings */ |
2609 | |
2610 | sptr = sbuf; |
2611 | ptr = stabslines; |
2612 | numstabs = 0; |
2613 | |
2614 | if (ptr) { |
2615 | /* |
2616 | * this is the first stab, its strx points to the filename of the |
2617 | * the source-file, the n_desc field should be set to the number |
2618 | * of remaining stabs |
2619 | */ |
2620 | WRITE_STAB(sptr, fileidx[0], 0, 0, 0, stabstrlen); |
2621 | |
2622 | /* this is the stab for the main source file */ |
2623 | WRITE_STAB(sptr, fileidx[mainfileindex], N_SO, 0, 0, 0); |
2624 | |
2625 | /* relocation table entry */ |
2626 | |
2627 | /* |
2628 | * Since the symbol table has two entries before |
2629 | * the section symbols, the index in the info.section |
2630 | * member must be adjusted by adding 2 |
2631 | */ |
2632 | |
2633 | if (is_elf32()) { |
2634 | WRITELONG(rptr, (sptr - sbuf) - 4); |
2635 | WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_386_32); |
2636 | } else if (is_elfx32()) { |
2637 | WRITELONG(rptr, (sptr - sbuf) - 4); |
2638 | WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_X86_64_32); |
2639 | WRITELONG(rptr, 0); |
2640 | } else { |
2641 | nasm_assert(is_elf64()); |
2642 | WRITEDLONG(rptr, (int64_t)(sptr - sbuf) - 4); |
2643 | WRITELONG(rptr, R_X86_64_32); |
2644 | WRITELONG(rptr, ptr->info.section + 2); |
2645 | WRITEDLONG(rptr, 0); |
2646 | } |
2647 | numstabs++; |
2648 | } |
2649 | |
2650 | if (is_elf32()) { |
2651 | while (ptr) { |
2652 | if (strcmp(allfiles[currfile], ptr->filename)) { |
2653 | /* oops file has changed... */ |
2654 | for (i = 0; i < numfiles; i++) |
2655 | if (!strcmp(allfiles[i], ptr->filename)) |
2656 | break; |
2657 | currfile = i; |
2658 | WRITE_STAB(sptr, fileidx[currfile], N_SOL, 0, 0, |
2659 | ptr->info.offset); |
2660 | numstabs++; |
2661 | |
2662 | /* relocation table entry */ |
2663 | WRITELONG(rptr, (sptr - sbuf) - 4); |
2664 | WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_386_32); |
2665 | } |
2666 | |
2667 | WRITE_STAB(sptr, 0, N_SLINE, 0, ptr->line, ptr->info.offset); |
2668 | numstabs++; |
2669 | |
2670 | /* relocation table entry */ |
2671 | WRITELONG(rptr, (sptr - sbuf) - 4); |
2672 | WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_386_32); |
2673 | |
2674 | ptr = ptr->next; |
2675 | } |
2676 | } else if (is_elfx32()) { |
2677 | while (ptr) { |
2678 | if (strcmp(allfiles[currfile], ptr->filename)) { |
2679 | /* oops file has changed... */ |
2680 | for (i = 0; i < numfiles; i++) |
2681 | if (!strcmp(allfiles[i], ptr->filename)) |
2682 | break; |
2683 | currfile = i; |
2684 | WRITE_STAB(sptr, fileidx[currfile], N_SOL, 0, 0, |
2685 | ptr->info.offset); |
2686 | numstabs++; |
2687 | |
2688 | /* relocation table entry */ |
2689 | WRITELONG(rptr, (sptr - sbuf) - 4); |
2690 | WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_X86_64_32); |
2691 | WRITELONG(rptr, ptr->info.offset); |
2692 | } |
2693 | |
2694 | WRITE_STAB(sptr, 0, N_SLINE, 0, ptr->line, ptr->info.offset); |
2695 | numstabs++; |
2696 | |
2697 | /* relocation table entry */ |
2698 | WRITELONG(rptr, (sptr - sbuf) - 4); |
2699 | WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_X86_64_32); |
2700 | WRITELONG(rptr, ptr->info.offset); |
2701 | |
2702 | ptr = ptr->next; |
2703 | } |
2704 | } else { |
2705 | nasm_assert(is_elf64()); |
2706 | while (ptr) { |
2707 | if (strcmp(allfiles[currfile], ptr->filename)) { |
2708 | /* oops file has changed... */ |
2709 | for (i = 0; i < numfiles; i++) |
2710 | if (!strcmp(allfiles[i], ptr->filename)) |
2711 | break; |
2712 | currfile = i; |
2713 | WRITE_STAB(sptr, fileidx[currfile], N_SOL, 0, 0, |
2714 | ptr->info.offset); |
2715 | numstabs++; |
2716 | |
2717 | /* relocation table entry */ |
2718 | WRITEDLONG(rptr, (int64_t)(sptr - sbuf) - 4); |
2719 | WRITELONG(rptr, R_X86_64_32); |
2720 | WRITELONG(rptr, ptr->info.section + 2); |
2721 | WRITEDLONG(rptr, ptr->info.offset); |
2722 | } |
2723 | |
2724 | WRITE_STAB(sptr, 0, N_SLINE, 0, ptr->line, ptr->info.offset); |
2725 | numstabs++; |
2726 | |
2727 | /* relocation table entry */ |
2728 | WRITEDLONG(rptr, (int64_t)(sptr - sbuf) - 4); |
2729 | WRITELONG(rptr, R_X86_64_32); |
2730 | WRITELONG(rptr, ptr->info.section + 2); |
2731 | WRITEDLONG(rptr, ptr->info.offset); |
2732 | |
2733 | ptr = ptr->next; |
2734 | } |
2735 | } |
2736 | |
2737 | /* this is an "ending" token */ |
2738 | WRITE_STAB(sptr, 0, N_SO, 0, 0, 0); |
2739 | numstabs++; |
2740 | |
2741 | ((struct stabentry *)sbuf)->n_desc = numstabs; |
2742 | |
2743 | nasm_free(allfiles); |
2744 | nasm_free(fileidx); |
2745 | |
2746 | stablen = (sptr - sbuf); |
2747 | stabrellen = (rptr - rbuf); |
2748 | stabrelbuf = rbuf; |
2749 | stabbuf = sbuf; |
2750 | stabstrbuf = ssbuf; |
2751 | } |
2752 | |
2753 | static void stabs_cleanup(void) |
2754 | { |
2755 | struct linelist *ptr, *del; |
2756 | if (!stabslines) |
2757 | return; |
2758 | |
2759 | ptr = stabslines; |
2760 | while (ptr) { |
2761 | del = ptr; |
2762 | ptr = ptr->next; |
2763 | nasm_free(del); |
2764 | } |
2765 | |
2766 | nasm_free(stabbuf); |
2767 | nasm_free(stabrelbuf); |
2768 | nasm_free(stabstrbuf); |
2769 | } |
2770 | |
2771 | /* dwarf routines */ |
2772 | |
2773 | static void dwarf_init(void) |
2774 | { |
2775 | ndebugs = 3; /* 3 debug symbols */ |
2776 | } |
2777 | |
2778 | static void dwarf_linenum(const char *filename, int32_t linenumber, |
2779 | int32_t segto) |
2780 | { |
2781 | (void)segto; |
2782 | dwarf_findfile(filename); |
2783 | debug_immcall = 1; |
2784 | currentline = linenumber; |
2785 | } |
2786 | |
2787 | /* called from elf_out with type == TY_DEBUGSYMLIN */ |
2788 | static void dwarf_output(int type, void *param) |
2789 | { |
2790 | int ln, aa, inx, maxln, soc; |
2791 | struct symlininfo *s; |
2792 | struct SAA *plinep; |
2793 | |
2794 | (void)type; |
2795 | |
2796 | s = (struct symlininfo *)param; |
2797 | |
2798 | /* line number info is only gathered for executable sections */ |
2799 | if (!(sects[s->section]->flags & SHF_EXECINSTR)) |
2800 | return; |
2801 | |
2802 | /* Check if section index has changed */ |
2803 | if (!(dwarf_csect && (dwarf_csect->section) == (s->section))) |
2804 | dwarf_findsect(s->section); |
2805 | |
2806 | /* do nothing unless line or file has changed */ |
2807 | if (!debug_immcall) |
2808 | return; |
2809 | |
2810 | ln = currentline - dwarf_csect->line; |
2811 | aa = s->offset - dwarf_csect->offset; |
2812 | inx = dwarf_clist->line; |
2813 | plinep = dwarf_csect->psaa; |
2814 | /* check for file change */ |
2815 | if (!(inx == dwarf_csect->file)) { |
2816 | saa_write8(plinep,DW_LNS_set_file); |
2817 | saa_write8(plinep,inx); |
2818 | dwarf_csect->file = inx; |
2819 | } |
2820 | /* check for line change */ |
2821 | if (ln) { |
2822 | /* test if in range of special op code */ |
2823 | maxln = line_base + line_range; |
2824 | soc = (ln - line_base) + (line_range * aa) + opcode_base; |
2825 | if (ln >= line_base && ln < maxln && soc < 256) { |
2826 | saa_write8(plinep,soc); |
2827 | } else { |
2828 | saa_write8(plinep,DW_LNS_advance_line); |
2829 | saa_wleb128s(plinep,ln); |
2830 | if (aa) { |
2831 | saa_write8(plinep,DW_LNS_advance_pc); |
2832 | saa_wleb128u(plinep,aa); |
2833 | } |
2834 | saa_write8(plinep,DW_LNS_copy); |
2835 | } |
2836 | dwarf_csect->line = currentline; |
2837 | dwarf_csect->offset = s->offset; |
2838 | } |
2839 | |
2840 | /* show change handled */ |
2841 | debug_immcall = 0; |
2842 | } |
2843 | |
2844 | |
2845 | static void dwarf_generate(void) |
2846 | { |
2847 | uint8_t *pbuf; |
2848 | int indx; |
2849 | struct linelist *ftentry; |
2850 | struct SAA *paranges, *ppubnames, *pinfo, *pabbrev, *plines, *plinep; |
2851 | struct SAA *parangesrel, *plinesrel, *pinforel; |
2852 | struct sectlist *psect; |
2853 | size_t saalen, linepoff, totlen, highaddr; |
2854 | |
2855 | if (is_elf32()) { |
2856 | /* write epilogues for each line program range */ |
2857 | /* and build aranges section */ |
2858 | paranges = saa_init(1L); |
2859 | parangesrel = saa_init(1L); |
2860 | saa_write16(paranges,2); /* dwarf version */ |
2861 | saa_write32(parangesrel, paranges->datalen+4); |
2862 | saa_write32(parangesrel, (dwarf_infosym << 8) + R_386_32); /* reloc to info */ |
2863 | saa_write32(parangesrel, 0); |
2864 | saa_write32(paranges,0); /* offset into info */ |
2865 | saa_write8(paranges,4); /* pointer size */ |
2866 | saa_write8(paranges,0); /* not segmented */ |
2867 | saa_write32(paranges,0); /* padding */ |
2868 | /* iterate though sectlist entries */ |
2869 | psect = dwarf_fsect; |
2870 | totlen = 0; |
2871 | highaddr = 0; |
2872 | for (indx = 0; indx < dwarf_nsections; indx++) { |
2873 | plinep = psect->psaa; |
2874 | /* Line Number Program Epilogue */ |
2875 | saa_write8(plinep,2); /* std op 2 */ |
2876 | saa_write8(plinep,(sects[psect->section]->len)-psect->offset); |
2877 | saa_write8(plinep,DW_LNS_extended_op); |
2878 | saa_write8(plinep,1); /* operand length */ |
2879 | saa_write8(plinep,DW_LNE_end_sequence); |
2880 | totlen += plinep->datalen; |
2881 | /* range table relocation entry */ |
2882 | saa_write32(parangesrel, paranges->datalen + 4); |
2883 | saa_write32(parangesrel, ((uint32_t) (psect->section + 2) << 8) + R_386_32); |
2884 | saa_write32(parangesrel, (uint32_t) 0); |
2885 | /* range table entry */ |
2886 | saa_write32(paranges,0x0000); /* range start */ |
2887 | saa_write32(paranges,sects[psect->section]->len); /* range length */ |
2888 | highaddr += sects[psect->section]->len; |
2889 | /* done with this entry */ |
2890 | psect = psect->next; |
2891 | } |
2892 | saa_write32(paranges,0); /* null address */ |
2893 | saa_write32(paranges,0); /* null length */ |
2894 | saalen = paranges->datalen; |
2895 | arangeslen = saalen + 4; |
2896 | arangesbuf = pbuf = nasm_malloc(arangeslen); |
2897 | WRITELONG(pbuf,saalen); /* initial length */ |
2898 | saa_rnbytes(paranges, pbuf, saalen); |
2899 | saa_free(paranges); |
2900 | } else if (is_elfx32()) { |
2901 | /* write epilogues for each line program range */ |
2902 | /* and build aranges section */ |
2903 | paranges = saa_init(1L); |
2904 | parangesrel = saa_init(1L); |
2905 | saa_write16(paranges,3); /* dwarf version */ |
2906 | saa_write32(parangesrel, paranges->datalen+4); |
2907 | saa_write32(parangesrel, (dwarf_infosym << 8) + R_X86_64_32); /* reloc to info */ |
2908 | saa_write32(parangesrel, 0); |
2909 | saa_write32(paranges,0); /* offset into info */ |
2910 | saa_write8(paranges,4); /* pointer size */ |
2911 | saa_write8(paranges,0); /* not segmented */ |
2912 | saa_write32(paranges,0); /* padding */ |
2913 | /* iterate though sectlist entries */ |
2914 | psect = dwarf_fsect; |
2915 | totlen = 0; |
2916 | highaddr = 0; |
2917 | for (indx = 0; indx < dwarf_nsections; indx++) { |
2918 | plinep = psect->psaa; |
2919 | /* Line Number Program Epilogue */ |
2920 | saa_write8(plinep,2); /* std op 2 */ |
2921 | saa_write8(plinep,(sects[psect->section]->len)-psect->offset); |
2922 | saa_write8(plinep,DW_LNS_extended_op); |
2923 | saa_write8(plinep,1); /* operand length */ |
2924 | saa_write8(plinep,DW_LNE_end_sequence); |
2925 | totlen += plinep->datalen; |
2926 | /* range table relocation entry */ |
2927 | saa_write32(parangesrel, paranges->datalen + 4); |
2928 | saa_write32(parangesrel, ((uint32_t) (psect->section + 2) << 8) + R_X86_64_32); |
2929 | saa_write32(parangesrel, (uint32_t) 0); |
2930 | /* range table entry */ |
2931 | saa_write32(paranges,0x0000); /* range start */ |
2932 | saa_write32(paranges,sects[psect->section]->len); /* range length */ |
2933 | highaddr += sects[psect->section]->len; |
2934 | /* done with this entry */ |
2935 | psect = psect->next; |
2936 | } |
2937 | saa_write32(paranges,0); /* null address */ |
2938 | saa_write32(paranges,0); /* null length */ |
2939 | saalen = paranges->datalen; |
2940 | arangeslen = saalen + 4; |
2941 | arangesbuf = pbuf = nasm_malloc(arangeslen); |
2942 | WRITELONG(pbuf,saalen); /* initial length */ |
2943 | saa_rnbytes(paranges, pbuf, saalen); |
2944 | saa_free(paranges); |
2945 | } else { |
2946 | nasm_assert(is_elf64()); |
2947 | /* write epilogues for each line program range */ |
2948 | /* and build aranges section */ |
2949 | paranges = saa_init(1L); |
2950 | parangesrel = saa_init(1L); |
2951 | saa_write16(paranges,3); /* dwarf version */ |
2952 | saa_write64(parangesrel, paranges->datalen+4); |
2953 | saa_write64(parangesrel, (dwarf_infosym << 32) + R_X86_64_32); /* reloc to info */ |
2954 | saa_write64(parangesrel, 0); |
2955 | saa_write32(paranges,0); /* offset into info */ |
2956 | saa_write8(paranges,8); /* pointer size */ |
2957 | saa_write8(paranges,0); /* not segmented */ |
2958 | saa_write32(paranges,0); /* padding */ |
2959 | /* iterate though sectlist entries */ |
2960 | psect = dwarf_fsect; |
2961 | totlen = 0; |
2962 | highaddr = 0; |
2963 | for (indx = 0; indx < dwarf_nsections; indx++) { |
2964 | plinep = psect->psaa; |
2965 | /* Line Number Program Epilogue */ |
2966 | saa_write8(plinep,2); /* std op 2 */ |
2967 | saa_write8(plinep,(sects[psect->section]->len)-psect->offset); |
2968 | saa_write8(plinep,DW_LNS_extended_op); |
2969 | saa_write8(plinep,1); /* operand length */ |
2970 | saa_write8(plinep,DW_LNE_end_sequence); |
2971 | totlen += plinep->datalen; |
2972 | /* range table relocation entry */ |
2973 | saa_write64(parangesrel, paranges->datalen + 4); |
2974 | saa_write64(parangesrel, ((uint64_t) (psect->section + 2) << 32) + R_X86_64_64); |
2975 | saa_write64(parangesrel, (uint64_t) 0); |
2976 | /* range table entry */ |
2977 | saa_write64(paranges,0x0000); /* range start */ |
2978 | saa_write64(paranges,sects[psect->section]->len); /* range length */ |
2979 | highaddr += sects[psect->section]->len; |
2980 | /* done with this entry */ |
2981 | psect = psect->next; |
2982 | } |
2983 | saa_write64(paranges,0); /* null address */ |
2984 | saa_write64(paranges,0); /* null length */ |
2985 | saalen = paranges->datalen; |
2986 | arangeslen = saalen + 4; |
2987 | arangesbuf = pbuf = nasm_malloc(arangeslen); |
2988 | WRITELONG(pbuf,saalen); /* initial length */ |
2989 | saa_rnbytes(paranges, pbuf, saalen); |
2990 | saa_free(paranges); |
2991 | } |
2992 | |
2993 | /* build rela.aranges section */ |
2994 | arangesrellen = saalen = parangesrel->datalen; |
2995 | arangesrelbuf = pbuf = nasm_malloc(arangesrellen); |
2996 | saa_rnbytes(parangesrel, pbuf, saalen); |
2997 | saa_free(parangesrel); |
2998 | |
2999 | /* build pubnames section */ |
3000 | ppubnames = saa_init(1L); |
3001 | saa_write16(ppubnames,3); /* dwarf version */ |
3002 | saa_write32(ppubnames,0); /* offset into info */ |
3003 | saa_write32(ppubnames,0); /* space used in info */ |
3004 | saa_write32(ppubnames,0); /* end of list */ |
3005 | saalen = ppubnames->datalen; |
3006 | pubnameslen = saalen + 4; |
3007 | pubnamesbuf = pbuf = nasm_malloc(pubnameslen); |
3008 | WRITELONG(pbuf,saalen); /* initial length */ |
3009 | saa_rnbytes(ppubnames, pbuf, saalen); |
3010 | saa_free(ppubnames); |
3011 | |
3012 | if (is_elf32()) { |
3013 | /* build info section */ |
3014 | pinfo = saa_init(1L); |
3015 | pinforel = saa_init(1L); |
3016 | saa_write16(pinfo,2); /* dwarf version */ |
3017 | saa_write32(pinforel, pinfo->datalen + 4); |
3018 | saa_write32(pinforel, (dwarf_abbrevsym << 8) + R_386_32); /* reloc to abbrev */ |
3019 | saa_write32(pinforel, 0); |
3020 | saa_write32(pinfo,0); /* offset into abbrev */ |
3021 | saa_write8(pinfo,4); /* pointer size */ |
3022 | saa_write8(pinfo,1); /* abbrviation number LEB128u */ |
3023 | saa_write32(pinforel, pinfo->datalen + 4); |
3024 | saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_386_32); |
3025 | saa_write32(pinforel, 0); |
3026 | saa_write32(pinfo,0); /* DW_AT_low_pc */ |
3027 | saa_write32(pinforel, pinfo->datalen + 4); |
3028 | saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_386_32); |
3029 | saa_write32(pinforel, 0); |
3030 | saa_write32(pinfo,highaddr); /* DW_AT_high_pc */ |
3031 | saa_write32(pinforel, pinfo->datalen + 4); |
3032 | saa_write32(pinforel, (dwarf_linesym << 8) + R_386_32); /* reloc to line */ |
3033 | saa_write32(pinforel, 0); |
3034 | saa_write32(pinfo,0); /* DW_AT_stmt_list */ |
3035 | saa_wbytes(pinfo, elf_module, strlen(elf_module)+1); |
3036 | saa_wbytes(pinfo, nasm_signature, strlen(nasm_signature)+1); |
3037 | saa_write16(pinfo,DW_LANG_Mips_Assembler); |
3038 | saa_write8(pinfo,2); /* abbrviation number LEB128u */ |
3039 | saa_write32(pinforel, pinfo->datalen + 4); |
3040 | saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_386_32); |
3041 | saa_write32(pinforel, 0); |
3042 | saa_write32(pinfo,0); /* DW_AT_low_pc */ |
3043 | saa_write32(pinfo,0); /* DW_AT_frame_base */ |
3044 | saa_write8(pinfo,0); /* end of entries */ |
3045 | saalen = pinfo->datalen; |
3046 | infolen = saalen + 4; |
3047 | infobuf = pbuf = nasm_malloc(infolen); |
3048 | WRITELONG(pbuf,saalen); /* initial length */ |
3049 | saa_rnbytes(pinfo, pbuf, saalen); |
3050 | saa_free(pinfo); |
3051 | } else if (is_elfx32()) { |
3052 | /* build info section */ |
3053 | pinfo = saa_init(1L); |
3054 | pinforel = saa_init(1L); |
3055 | saa_write16(pinfo,3); /* dwarf version */ |
3056 | saa_write32(pinforel, pinfo->datalen + 4); |
3057 | saa_write32(pinforel, (dwarf_abbrevsym << 8) + R_X86_64_32); /* reloc to abbrev */ |
3058 | saa_write32(pinforel, 0); |
3059 | saa_write32(pinfo,0); /* offset into abbrev */ |
3060 | saa_write8(pinfo,4); /* pointer size */ |
3061 | saa_write8(pinfo,1); /* abbrviation number LEB128u */ |
3062 | saa_write32(pinforel, pinfo->datalen + 4); |
3063 | saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_X86_64_32); |
3064 | saa_write32(pinforel, 0); |
3065 | saa_write32(pinfo,0); /* DW_AT_low_pc */ |
3066 | saa_write32(pinforel, pinfo->datalen + 4); |
3067 | saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_X86_64_32); |
3068 | saa_write32(pinforel, 0); |
3069 | saa_write32(pinfo,highaddr); /* DW_AT_high_pc */ |
3070 | saa_write32(pinforel, pinfo->datalen + 4); |
3071 | saa_write32(pinforel, (dwarf_linesym << 8) + R_X86_64_32); /* reloc to line */ |
3072 | saa_write32(pinforel, 0); |
3073 | saa_write32(pinfo,0); /* DW_AT_stmt_list */ |
3074 | saa_wbytes(pinfo, elf_module, strlen(elf_module)+1); |
3075 | saa_wbytes(pinfo, nasm_signature, strlen(nasm_signature)+1); |
3076 | saa_write16(pinfo,DW_LANG_Mips_Assembler); |
3077 | saa_write8(pinfo,2); /* abbrviation number LEB128u */ |
3078 | saa_write32(pinforel, pinfo->datalen + 4); |
3079 | saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_X86_64_32); |
3080 | saa_write32(pinforel, 0); |
3081 | saa_write32(pinfo,0); /* DW_AT_low_pc */ |
3082 | saa_write32(pinfo,0); /* DW_AT_frame_base */ |
3083 | saa_write8(pinfo,0); /* end of entries */ |
3084 | saalen = pinfo->datalen; |
3085 | infolen = saalen + 4; |
3086 | infobuf = pbuf = nasm_malloc(infolen); |
3087 | WRITELONG(pbuf,saalen); /* initial length */ |
3088 | saa_rnbytes(pinfo, pbuf, saalen); |
3089 | saa_free(pinfo); |
3090 | } else { |
3091 | nasm_assert(is_elf64()); |
3092 | /* build info section */ |
3093 | pinfo = saa_init(1L); |
3094 | pinforel = saa_init(1L); |
3095 | saa_write16(pinfo,3); /* dwarf version */ |
3096 | saa_write64(pinforel, pinfo->datalen + 4); |
3097 | saa_write64(pinforel, (dwarf_abbrevsym << 32) + R_X86_64_32); /* reloc to abbrev */ |
3098 | saa_write64(pinforel, 0); |
3099 | saa_write32(pinfo,0); /* offset into abbrev */ |
3100 | saa_write8(pinfo,8); /* pointer size */ |
3101 | saa_write8(pinfo,1); /* abbrviation number LEB128u */ |
3102 | saa_write64(pinforel, pinfo->datalen + 4); |
3103 | saa_write64(pinforel, ((uint64_t)(dwarf_fsect->section + 2) << 32) + R_X86_64_64); |
3104 | saa_write64(pinforel, 0); |
3105 | saa_write64(pinfo,0); /* DW_AT_low_pc */ |
3106 | saa_write64(pinforel, pinfo->datalen + 4); |
3107 | saa_write64(pinforel, ((uint64_t)(dwarf_fsect->section + 2) << 32) + R_X86_64_64); |
3108 | saa_write64(pinforel, 0); |
3109 | saa_write64(pinfo,highaddr); /* DW_AT_high_pc */ |
3110 | saa_write64(pinforel, pinfo->datalen + 4); |
3111 | saa_write64(pinforel, (dwarf_linesym << 32) + R_X86_64_32); /* reloc to line */ |
3112 | saa_write64(pinforel, 0); |
3113 | saa_write32(pinfo,0); /* DW_AT_stmt_list */ |
3114 | saa_wbytes(pinfo, elf_module, strlen(elf_module)+1); |
3115 | saa_wbytes(pinfo, nasm_signature, strlen(nasm_signature)+1); |
3116 | saa_write16(pinfo,DW_LANG_Mips_Assembler); |
3117 | saa_write8(pinfo,2); /* abbrviation number LEB128u */ |
3118 | saa_write64(pinforel, pinfo->datalen + 4); |
3119 | saa_write64(pinforel, ((uint64_t)(dwarf_fsect->section + 2) << 32) + R_X86_64_64); |
3120 | saa_write64(pinforel, 0); |
3121 | saa_write64(pinfo,0); /* DW_AT_low_pc */ |
3122 | saa_write64(pinfo,0); /* DW_AT_frame_base */ |
3123 | saa_write8(pinfo,0); /* end of entries */ |
3124 | saalen = pinfo->datalen; |
3125 | infolen = saalen + 4; |
3126 | infobuf = pbuf = nasm_malloc(infolen); |
3127 | WRITELONG(pbuf,saalen); /* initial length */ |
3128 | saa_rnbytes(pinfo, pbuf, saalen); |
3129 | saa_free(pinfo); |
3130 | } |
3131 | |
3132 | /* build rela.info section */ |
3133 | inforellen = saalen = pinforel->datalen; |
3134 | inforelbuf = pbuf = nasm_malloc(inforellen); |
3135 | saa_rnbytes(pinforel, pbuf, saalen); |
3136 | saa_free(pinforel); |
3137 | |
3138 | /* build abbrev section */ |
3139 | pabbrev = saa_init(1L); |
3140 | saa_write8(pabbrev,1); /* entry number LEB128u */ |
3141 | saa_write8(pabbrev,DW_TAG_compile_unit); /* tag LEB128u */ |
3142 | saa_write8(pabbrev,1); /* has children */ |
3143 | /* the following attributes and forms are all LEB128u values */ |
3144 | saa_write8(pabbrev,DW_AT_low_pc); |
3145 | saa_write8(pabbrev,DW_FORM_addr); |
3146 | saa_write8(pabbrev,DW_AT_high_pc); |
3147 | saa_write8(pabbrev,DW_FORM_addr); |
3148 | saa_write8(pabbrev,DW_AT_stmt_list); |
3149 | saa_write8(pabbrev,DW_FORM_data4); |
3150 | saa_write8(pabbrev,DW_AT_name); |
3151 | saa_write8(pabbrev,DW_FORM_string); |
3152 | saa_write8(pabbrev,DW_AT_producer); |
3153 | saa_write8(pabbrev,DW_FORM_string); |
3154 | saa_write8(pabbrev,DW_AT_language); |
3155 | saa_write8(pabbrev,DW_FORM_data2); |
3156 | saa_write16(pabbrev,0); /* end of entry */ |
3157 | /* LEB128u usage same as above */ |
3158 | saa_write8(pabbrev,2); /* entry number */ |
3159 | saa_write8(pabbrev,DW_TAG_subprogram); |
3160 | saa_write8(pabbrev,0); /* no children */ |
3161 | saa_write8(pabbrev,DW_AT_low_pc); |
3162 | saa_write8(pabbrev,DW_FORM_addr); |
3163 | saa_write8(pabbrev,DW_AT_frame_base); |
3164 | saa_write8(pabbrev,DW_FORM_data4); |
3165 | saa_write16(pabbrev,0); /* end of entry */ |
3166 | /* Terminal zero entry */ |
3167 | saa_write8(pabbrev,0); |
3168 | abbrevlen = saalen = pabbrev->datalen; |
3169 | abbrevbuf = pbuf = nasm_malloc(saalen); |
3170 | saa_rnbytes(pabbrev, pbuf, saalen); |
3171 | saa_free(pabbrev); |
3172 | |
3173 | /* build line section */ |
3174 | /* prolog */ |
3175 | plines = saa_init(1L); |
3176 | saa_write8(plines,1); /* Minimum Instruction Length */ |
3177 | saa_write8(plines,1); /* Initial value of 'is_stmt' */ |
3178 | saa_write8(plines,line_base); /* Line Base */ |
3179 | saa_write8(plines,line_range); /* Line Range */ |
3180 | saa_write8(plines,opcode_base); /* Opcode Base */ |
3181 | /* standard opcode lengths (# of LEB128u operands) */ |
3182 | saa_write8(plines,0); /* Std opcode 1 length */ |
3183 | saa_write8(plines,1); /* Std opcode 2 length */ |
3184 | saa_write8(plines,1); /* Std opcode 3 length */ |
3185 | saa_write8(plines,1); /* Std opcode 4 length */ |
3186 | saa_write8(plines,1); /* Std opcode 5 length */ |
3187 | saa_write8(plines,0); /* Std opcode 6 length */ |
3188 | saa_write8(plines,0); /* Std opcode 7 length */ |
3189 | saa_write8(plines,0); /* Std opcode 8 length */ |
3190 | saa_write8(plines,1); /* Std opcode 9 length */ |
3191 | saa_write8(plines,0); /* Std opcode 10 length */ |
3192 | saa_write8(plines,0); /* Std opcode 11 length */ |
3193 | saa_write8(plines,1); /* Std opcode 12 length */ |
3194 | /* Directory Table */ |
3195 | saa_write8(plines,0); /* End of table */ |
3196 | /* File Name Table */ |
3197 | ftentry = dwarf_flist; |
3198 | for (indx = 0; indx < dwarf_numfiles; indx++) { |
3199 | saa_wbytes(plines, ftentry->filename, (int32_t)(strlen(ftentry->filename) + 1)); |
3200 | saa_write8(plines,0); /* directory LEB128u */ |
3201 | saa_write8(plines,0); /* time LEB128u */ |
3202 | saa_write8(plines,0); /* size LEB128u */ |
3203 | ftentry = ftentry->next; |
3204 | } |
3205 | saa_write8(plines,0); /* End of table */ |
3206 | linepoff = plines->datalen; |
3207 | linelen = linepoff + totlen + 10; |
3208 | linebuf = pbuf = nasm_malloc(linelen); |
3209 | WRITELONG(pbuf,linelen-4); /* initial length */ |
3210 | WRITESHORT(pbuf,3); /* dwarf version */ |
3211 | WRITELONG(pbuf,linepoff); /* offset to line number program */ |
3212 | /* write line header */ |
3213 | saalen = linepoff; |
3214 | saa_rnbytes(plines, pbuf, saalen); /* read a given no. of bytes */ |
3215 | pbuf += linepoff; |
3216 | saa_free(plines); |
3217 | /* concatonate line program ranges */ |
3218 | linepoff += 13; |
3219 | plinesrel = saa_init(1L); |
3220 | psect = dwarf_fsect; |
3221 | if (is_elf32()) { |
3222 | for (indx = 0; indx < dwarf_nsections; indx++) { |
3223 | saa_write32(plinesrel, linepoff); |
3224 | saa_write32(plinesrel, ((uint32_t) (psect->section + 2) << 8) + R_386_32); |
3225 | saa_write32(plinesrel, (uint32_t) 0); |
3226 | plinep = psect->psaa; |
3227 | saalen = plinep->datalen; |
3228 | saa_rnbytes(plinep, pbuf, saalen); |
3229 | pbuf += saalen; |
3230 | linepoff += saalen; |
3231 | saa_free(plinep); |
3232 | /* done with this entry */ |
3233 | psect = psect->next; |
3234 | } |
3235 | } else if (is_elfx32()) { |
3236 | for (indx = 0; indx < dwarf_nsections; indx++) { |
3237 | saa_write32(plinesrel, linepoff); |
3238 | saa_write32(plinesrel, ((psect->section + 2) << 8) + R_X86_64_32); |
3239 | saa_write32(plinesrel, 0); |
3240 | plinep = psect->psaa; |
3241 | saalen = plinep->datalen; |
3242 | saa_rnbytes(plinep, pbuf, saalen); |
3243 | pbuf += saalen; |
3244 | linepoff += saalen; |
3245 | saa_free(plinep); |
3246 | /* done with this entry */ |
3247 | psect = psect->next; |
3248 | } |
3249 | } else { |
3250 | nasm_assert(is_elf64()); |
3251 | for (indx = 0; indx < dwarf_nsections; indx++) { |
3252 | saa_write64(plinesrel, linepoff); |
3253 | saa_write64(plinesrel, ((uint64_t) (psect->section + 2) << 32) + R_X86_64_64); |
3254 | saa_write64(plinesrel, (uint64_t) 0); |
3255 | plinep = psect->psaa; |
3256 | saalen = plinep->datalen; |
3257 | saa_rnbytes(plinep, pbuf, saalen); |
3258 | pbuf += saalen; |
3259 | linepoff += saalen; |
3260 | saa_free(plinep); |
3261 | /* done with this entry */ |
3262 | psect = psect->next; |
3263 | } |
3264 | } |
3265 | |
3266 | /* build rela.lines section */ |
3267 | linerellen =saalen = plinesrel->datalen; |
3268 | linerelbuf = pbuf = nasm_malloc(linerellen); |
3269 | saa_rnbytes(plinesrel, pbuf, saalen); |
3270 | saa_free(plinesrel); |
3271 | |
3272 | /* build frame section */ |
3273 | framelen = 4; |
3274 | framebuf = pbuf = nasm_malloc(framelen); |
3275 | WRITELONG(pbuf,framelen-4); /* initial length */ |
3276 | |
3277 | /* build loc section */ |
3278 | loclen = 16; |
3279 | locbuf = pbuf = nasm_malloc(loclen); |
3280 | if (is_elf32()) { |
3281 | WRITELONG(pbuf,0); /* null beginning offset */ |
3282 | WRITELONG(pbuf,0); /* null ending offset */ |
3283 | } else if (is_elfx32()) { |
3284 | WRITELONG(pbuf,0); /* null beginning offset */ |
3285 | WRITELONG(pbuf,0); /* null ending offset */ |
3286 | } else { |
3287 | nasm_assert(is_elf64()); |
3288 | WRITEDLONG(pbuf,0); /* null beginning offset */ |
3289 | WRITEDLONG(pbuf,0); /* null ending offset */ |
3290 | } |
3291 | } |
3292 | |
3293 | static void dwarf_cleanup(void) |
3294 | { |
3295 | nasm_free(arangesbuf); |
3296 | nasm_free(arangesrelbuf); |
3297 | nasm_free(pubnamesbuf); |
3298 | nasm_free(infobuf); |
3299 | nasm_free(inforelbuf); |
3300 | nasm_free(abbrevbuf); |
3301 | nasm_free(linebuf); |
3302 | nasm_free(linerelbuf); |
3303 | nasm_free(framebuf); |
3304 | nasm_free(locbuf); |
3305 | } |
3306 | |
3307 | static void dwarf_findfile(const char * fname) |
3308 | { |
3309 | int finx; |
3310 | struct linelist *match; |
3311 | |
3312 | /* return if fname is current file name */ |
3313 | if (dwarf_clist && !(strcmp(fname, dwarf_clist->filename))) |
3314 | return; |
3315 | |
3316 | /* search for match */ |
3317 | match = 0; |
3318 | if (dwarf_flist) { |
3319 | match = dwarf_flist; |
3320 | for (finx = 0; finx < dwarf_numfiles; finx++) { |
3321 | if (!(strcmp(fname, match->filename))) { |
3322 | dwarf_clist = match; |
3323 | return; |
3324 | } |
3325 | match = match->next; |
3326 | } |
3327 | } |
3328 | |
3329 | /* add file name to end of list */ |
3330 | dwarf_clist = nasm_malloc(sizeof(struct linelist)); |
3331 | dwarf_numfiles++; |
3332 | dwarf_clist->line = dwarf_numfiles; |
3333 | dwarf_clist->filename = nasm_malloc(strlen(fname) + 1); |
3334 | strcpy(dwarf_clist->filename,fname); |
3335 | dwarf_clist->next = 0; |
3336 | if (!dwarf_flist) { /* if first entry */ |
3337 | dwarf_flist = dwarf_elist = dwarf_clist; |
3338 | dwarf_clist->last = 0; |
3339 | } else { /* chain to previous entry */ |
3340 | dwarf_elist->next = dwarf_clist; |
3341 | dwarf_elist = dwarf_clist; |
3342 | } |
3343 | } |
3344 | |
3345 | static void dwarf_findsect(const int index) |
3346 | { |
3347 | int sinx; |
3348 | struct sectlist *match; |
3349 | struct SAA *plinep; |
3350 | |
3351 | /* return if index is current section index */ |
3352 | if (dwarf_csect && (dwarf_csect->section == index)) |
3353 | return; |
3354 | |
3355 | /* search for match */ |
3356 | match = 0; |
3357 | if (dwarf_fsect) { |
3358 | match = dwarf_fsect; |
3359 | for (sinx = 0; sinx < dwarf_nsections; sinx++) { |
3360 | if (match->section == index) { |
3361 | dwarf_csect = match; |
3362 | return; |
3363 | } |
3364 | match = match->next; |
3365 | } |
3366 | } |
3367 | |
3368 | /* add entry to end of list */ |
3369 | dwarf_csect = nasm_malloc(sizeof(struct sectlist)); |
3370 | dwarf_nsections++; |
3371 | dwarf_csect->psaa = plinep = saa_init(1L); |
3372 | dwarf_csect->line = 1; |
3373 | dwarf_csect->offset = 0; |
3374 | dwarf_csect->file = 1; |
3375 | dwarf_csect->section = index; |
3376 | dwarf_csect->next = 0; |
3377 | /* set relocatable address at start of line program */ |
3378 | saa_write8(plinep,DW_LNS_extended_op); |
3379 | saa_write8(plinep,is_elf64() ? 9 : 5); /* operand length */ |
3380 | saa_write8(plinep,DW_LNE_set_address); |
3381 | if (is_elf64()) |
3382 | saa_write64(plinep,0); /* Start Address */ |
3383 | else |
3384 | saa_write32(plinep,0); /* Start Address */ |
3385 | |
3386 | if (!dwarf_fsect) { /* if first entry */ |
3387 | dwarf_fsect = dwarf_esect = dwarf_csect; |
3388 | dwarf_csect->last = 0; |
3389 | } else { /* chain to previous entry */ |
3390 | dwarf_esect->next = dwarf_csect; |
3391 | dwarf_esect = dwarf_csect; |
3392 | } |
3393 | } |
3394 | |
3395 | #endif /* defined(OF_ELF32) || defined(OF_ELF64) || defined(OF_ELFX32) */ |
3396 | |