1 /*
2 * ELF object format helpers
3 *
4 * Copyright (C) 2003-2007 Michael Urman
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <util.h>
29
30 #include <libyasm.h>
31 #define YASM_OBJFMT_ELF_INTERNAL
32 #include "elf.h"
33 #include "elf-machine.h"
34
35 static void elf_section_data_destroy(void *data);
36 static void elf_secthead_print(void *data, FILE *f, int indent_level);
37
38 const yasm_assoc_data_callback elf_section_data = {
39 elf_section_data_destroy,
40 elf_secthead_print
41 };
42
43 static void elf_symrec_data_destroy(/*@only@*/ void *d);
44 static void elf_symtab_entry_print(void *data, FILE *f, int indent_level);
45 static void elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level);
46
47 const yasm_assoc_data_callback elf_symrec_data = {
48 elf_symrec_data_destroy,
49 elf_symtab_entry_print
50 };
51
52 const yasm_assoc_data_callback elf_ssym_symrec_data = {
53 elf_symrec_data_destroy,
54 elf_ssym_symtab_entry_print
55 };
56
57 extern elf_machine_handler
58 elf_machine_handler_x86_x86,
59 elf_machine_handler_x86_amd64;
60
61 static const elf_machine_handler *elf_machine_handlers[] =
62 {
63 &elf_machine_handler_x86_x86,
64 &elf_machine_handler_x86_amd64,
65 NULL
66 };
67 static const elf_machine_handler elf_null_machine = {0, 0, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0};
70 static elf_machine_handler const *elf_march = &elf_null_machine;
71 static yasm_symrec **elf_ssyms;
72
73 const elf_machine_handler *
elf_set_arch(yasm_arch * arch,yasm_symtab * symtab,int bits_pref)74 elf_set_arch(yasm_arch *arch, yasm_symtab *symtab, int bits_pref)
75 {
76 const char *machine = yasm_arch_get_machine(arch);
77 int i;
78
79 for (i=0, elf_march = elf_machine_handlers[0];
80 elf_march != NULL;
81 elf_march = elf_machine_handlers[++i])
82 {
83 if (yasm__strcasecmp(yasm_arch_keyword(arch), elf_march->arch)==0)
84 if (yasm__strcasecmp(machine, elf_march->machine)==0)
85 if (bits_pref == 0 || bits_pref == elf_march->bits)
86 break;
87 }
88
89 if (elf_march && elf_march->num_ssyms > 0)
90 {
91 /* Allocate "special" syms */
92 elf_ssyms =
93 yasm_xmalloc(elf_march->num_ssyms * sizeof(yasm_symrec *));
94 for (i=0; (unsigned int)i<elf_march->num_ssyms; i++)
95 {
96 /* FIXME: misuse of NULL bytecode */
97 elf_ssyms[i] = yasm_symtab_define_label(symtab,
98 elf_march->ssyms[i].name,
99 NULL, 0, 0);
100 yasm_symrec_add_data(elf_ssyms[i], &elf_ssym_symrec_data,
101 (void*)&elf_march->ssyms[i]);
102 }
103 }
104
105 return elf_march;
106 }
107
108 yasm_symrec *
elf_get_special_sym(const char * name,const char * parser)109 elf_get_special_sym(const char *name, const char *parser)
110 {
111 int i;
112 for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
113 if (yasm__strcasecmp(name, elf_march->ssyms[i].name) == 0)
114 return elf_ssyms[i];
115 }
116 return NULL;
117 }
118
119 /* reloc functions */
120 int elf_ssym_has_flag(yasm_symrec *wrt, int flag);
121
122 int
elf_is_wrt_sym_relative(yasm_symrec * wrt)123 elf_is_wrt_sym_relative(yasm_symrec *wrt)
124 {
125 return elf_ssym_has_flag(wrt, ELF_SSYM_SYM_RELATIVE);
126 }
127
128 int
elf_is_wrt_pos_adjusted(yasm_symrec * wrt)129 elf_is_wrt_pos_adjusted(yasm_symrec *wrt)
130 {
131 return elf_ssym_has_flag(wrt, ELF_SSYM_CURPOS_ADJUST);
132 }
133
134 int
elf_ssym_has_flag(yasm_symrec * wrt,int flag)135 elf_ssym_has_flag(yasm_symrec *wrt, int flag)
136 {
137 int i;
138 for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
139 if (elf_ssyms[i] == wrt)
140 return (elf_march->ssyms[i].sym_rel & flag) != 0;
141 }
142 return 0;
143 }
144
145 /* takes ownership of addr */
146 elf_reloc_entry *
elf_reloc_entry_create(yasm_symrec * sym,yasm_symrec * wrt,yasm_intnum * addr,int rel,size_t valsize,int is_GOT_sym)147 elf_reloc_entry_create(yasm_symrec *sym,
148 yasm_symrec *wrt,
149 yasm_intnum *addr,
150 int rel,
151 size_t valsize,
152 int is_GOT_sym)
153 {
154 elf_reloc_entry *entry;
155
156 if (!elf_march->accepts_reloc)
157 yasm_internal_error(N_("Unsupported machine for ELF output"));
158
159 if (!elf_march->accepts_reloc(valsize, wrt))
160 {
161 if (addr)
162 yasm_intnum_destroy(addr);
163 return NULL;
164 }
165
166 if (sym == NULL)
167 yasm_internal_error("sym is null");
168
169 entry = yasm_xmalloc(sizeof(elf_reloc_entry));
170 entry->reloc.sym = sym;
171 entry->reloc.addr = addr;
172 entry->rtype_rel = rel;
173 entry->valsize = valsize;
174 entry->addend = NULL;
175 entry->wrt = wrt;
176 entry->is_GOT_sym = is_GOT_sym;
177
178 return entry;
179 }
180
181 void
elf_reloc_entry_destroy(void * entry)182 elf_reloc_entry_destroy(void *entry)
183 {
184 if (((elf_reloc_entry*)entry)->addend)
185 yasm_intnum_destroy(((elf_reloc_entry*)entry)->addend);
186 yasm_xfree(entry);
187 }
188
189 /* strtab functions */
190 elf_strtab_entry *
elf_strtab_entry_create(const char * str)191 elf_strtab_entry_create(const char *str)
192 {
193 elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry));
194 entry->str = yasm__xstrdup(str);
195 entry->index = 0;
196 return entry;
197 }
198
199 void
elf_strtab_entry_set_str(elf_strtab_entry * entry,const char * str)200 elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str)
201 {
202 elf_strtab_entry *last;
203 if (entry->str)
204 yasm_xfree(entry->str);
205 entry->str = yasm__xstrdup(str);
206
207 /* Update all following indices since string length probably changes */
208 last = entry;
209 entry = STAILQ_NEXT(last, qlink);
210 while (entry) {
211 entry->index = last->index + (unsigned long)strlen(last->str) + 1;
212 last = entry;
213 entry = STAILQ_NEXT(last, qlink);
214 }
215 }
216
217 elf_strtab_head *
elf_strtab_create()218 elf_strtab_create()
219 {
220 elf_strtab_head *strtab = yasm_xmalloc(sizeof(elf_strtab_head));
221 elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry));
222
223 STAILQ_INIT(strtab);
224 entry->index = 0;
225 entry->str = yasm__xstrdup("");
226
227 STAILQ_INSERT_TAIL(strtab, entry, qlink);
228 return strtab;
229 }
230
231 elf_strtab_entry *
elf_strtab_append_str(elf_strtab_head * strtab,const char * str)232 elf_strtab_append_str(elf_strtab_head *strtab, const char *str)
233 {
234 elf_strtab_entry *last, *entry;
235
236 if (strtab == NULL)
237 yasm_internal_error("strtab is null");
238 if (STAILQ_EMPTY(strtab))
239 yasm_internal_error("strtab is missing initial dummy entry");
240
241 last = STAILQ_LAST(strtab, elf_strtab_entry, qlink);
242
243 entry = elf_strtab_entry_create(str);
244 entry->index = last->index + (unsigned long)strlen(last->str) + 1;
245
246 STAILQ_INSERT_TAIL(strtab, entry, qlink);
247 return entry;
248 }
249
250 void
elf_strtab_destroy(elf_strtab_head * strtab)251 elf_strtab_destroy(elf_strtab_head *strtab)
252 {
253 elf_strtab_entry *s1, *s2;
254
255 if (strtab == NULL)
256 yasm_internal_error("strtab is null");
257 if (STAILQ_EMPTY(strtab))
258 yasm_internal_error("strtab is missing initial dummy entry");
259
260 s1 = STAILQ_FIRST(strtab);
261 while (s1 != NULL) {
262 s2 = STAILQ_NEXT(s1, qlink);
263 yasm_xfree(s1->str);
264 yasm_xfree(s1);
265 s1 = s2;
266 }
267 yasm_xfree(strtab);
268 }
269
270 unsigned long
elf_strtab_output_to_file(FILE * f,elf_strtab_head * strtab)271 elf_strtab_output_to_file(FILE *f, elf_strtab_head *strtab)
272 {
273 unsigned long size = 0;
274 elf_strtab_entry *entry;
275
276 if (strtab == NULL)
277 yasm_internal_error("strtab is null");
278
279 /* consider optimizing tables here */
280 STAILQ_FOREACH(entry, strtab, qlink) {
281 size_t len = 1 + strlen(entry->str);
282 fwrite(entry->str, len, 1, f);
283 size += (unsigned long)len;
284 }
285 return size;
286 }
287
288
289
290 /* symtab functions */
291 elf_symtab_entry *
elf_symtab_entry_create(elf_strtab_entry * name,yasm_symrec * sym)292 elf_symtab_entry_create(elf_strtab_entry *name,
293 yasm_symrec *sym)
294 {
295 elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry));
296 entry->in_table = 0;
297 entry->sym = sym;
298 entry->sect = NULL;
299 entry->name = name;
300 entry->value = 0;
301
302 entry->xsize = NULL;
303 entry->size = 0;
304 entry->index = 0;
305 entry->bind = 0;
306 entry->type = STT_NOTYPE;
307 entry->vis = STV_DEFAULT;
308
309 return entry;
310 }
311
312 static void
elf_symtab_entry_destroy(elf_symtab_entry * entry)313 elf_symtab_entry_destroy(elf_symtab_entry *entry)
314 {
315 if (entry == NULL)
316 yasm_internal_error("symtab entry is null");
317
318 yasm_xfree(entry);
319 }
320
321 static void
elf_symrec_data_destroy(void * data)322 elf_symrec_data_destroy(void *data)
323 {
324 /* do nothing, as this stuff is in the symtab anyway... this speaks of bad
325 * design/use or this stuff, i fear */
326
327 /* watch for double-free here ... */
328 /*elf_symtab_entry_destroy((elf_symtab_entry *)data);*/
329 }
330
331 static void
elf_symtab_entry_print(void * data,FILE * f,int indent_level)332 elf_symtab_entry_print(void *data, FILE *f, int indent_level)
333 {
334 elf_symtab_entry *entry = data;
335 if (entry == NULL)
336 yasm_internal_error("symtab entry is null");
337
338 fprintf(f, "%*sbind=", indent_level, "");
339 switch (entry->bind) {
340 case STB_LOCAL: fprintf(f, "local\n"); break;
341 case STB_GLOBAL: fprintf(f, "global\n"); break;
342 case STB_WEAK: fprintf(f, "weak\n"); break;
343 default: fprintf(f, "undef\n"); break;
344 }
345 fprintf(f, "%*stype=", indent_level, "");
346 switch (entry->type) {
347 case STT_NOTYPE: fprintf(f, "notype\n"); break;
348 case STT_OBJECT: fprintf(f, "object\n"); break;
349 case STT_FUNC: fprintf(f, "func\n"); break;
350 case STT_SECTION: fprintf(f, "section\n");break;
351 case STT_FILE: fprintf(f, "file\n"); break;
352 default: fprintf(f, "undef\n"); break;
353 }
354 fprintf(f, "%*ssize=", indent_level, "");
355 if (entry->xsize)
356 yasm_expr_print(entry->xsize, f);
357 else
358 fprintf(f, "%ld", entry->size);
359 fprintf(f, "\n");
360 }
361
362 static void
elf_ssym_symtab_entry_print(void * data,FILE * f,int indent_level)363 elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level)
364 {
365 /* TODO */
366 }
367
368 elf_symtab_head *
elf_symtab_create()369 elf_symtab_create()
370 {
371 elf_symtab_head *symtab = yasm_xmalloc(sizeof(elf_symtab_head));
372 elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry));
373
374 STAILQ_INIT(symtab);
375 entry->in_table = 1;
376 entry->sym = NULL;
377 entry->sect = NULL;
378 entry->name = NULL;
379 entry->value = 0;
380 entry->xsize = NULL;
381 entry->size = 0;
382 entry->index = SHN_UNDEF;
383 entry->bind = STB_LOCAL;
384 entry->type = STT_NOTYPE;
385 entry->vis = STV_DEFAULT;
386 entry->symindex = 0;
387 STAILQ_INSERT_TAIL(symtab, entry, qlink);
388 return symtab;
389 }
390
391 void
elf_symtab_append_entry(elf_symtab_head * symtab,elf_symtab_entry * entry)392 elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry)
393 {
394 if (symtab == NULL)
395 yasm_internal_error("symtab is null");
396 if (entry == NULL)
397 yasm_internal_error("symtab entry is null");
398 if (STAILQ_EMPTY(symtab))
399 yasm_internal_error(N_("symtab is missing initial dummy entry"));
400
401 STAILQ_INSERT_TAIL(symtab, entry, qlink);
402 entry->in_table = 1;
403 }
404
405 void
elf_symtab_insert_local_sym(elf_symtab_head * symtab,elf_symtab_entry * entry)406 elf_symtab_insert_local_sym(elf_symtab_head *symtab, elf_symtab_entry *entry)
407 {
408 elf_symtab_entry *after = STAILQ_FIRST(symtab);
409 elf_symtab_entry *before = NULL;
410
411 while (after && (after->bind == STB_LOCAL)) {
412 before = after;
413 if (before->type == STT_FILE) break;
414 after = STAILQ_NEXT(after, qlink);
415 }
416 STAILQ_INSERT_AFTER(symtab, before, entry, qlink);
417 entry->in_table = 1;
418 }
419
420 void
elf_symtab_destroy(elf_symtab_head * symtab)421 elf_symtab_destroy(elf_symtab_head *symtab)
422 {
423 elf_symtab_entry *s1, *s2;
424
425 if (symtab == NULL)
426 yasm_internal_error("symtab is null");
427 if (STAILQ_EMPTY(symtab))
428 yasm_internal_error(N_("symtab is missing initial dummy entry"));
429
430 s1 = STAILQ_FIRST(symtab);
431 while (s1 != NULL) {
432 s2 = STAILQ_NEXT(s1, qlink);
433 elf_symtab_entry_destroy(s1);
434 s1 = s2;
435 }
436 yasm_xfree(symtab);
437 }
438
439 unsigned long
elf_symtab_assign_indices(elf_symtab_head * symtab)440 elf_symtab_assign_indices(elf_symtab_head *symtab)
441 {
442 elf_symtab_entry *entry, *prev=NULL;
443 unsigned long last_local=0;
444
445 if (symtab == NULL)
446 yasm_internal_error("symtab is null");
447 if (STAILQ_EMPTY(symtab))
448 yasm_internal_error(N_("symtab is missing initial dummy entry"));
449
450 STAILQ_FOREACH(entry, symtab, qlink) {
451 if (prev)
452 entry->symindex = prev->symindex + 1;
453 if (entry->bind == STB_LOCAL)
454 last_local = entry->symindex;
455 prev = entry;
456 }
457 return last_local + 1;
458 }
459
460 unsigned long
elf_symtab_write_to_file(FILE * f,elf_symtab_head * symtab,yasm_errwarns * errwarns)461 elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab,
462 yasm_errwarns *errwarns)
463 {
464 unsigned char buf[SYMTAB_MAXSIZE], *bufp;
465 elf_symtab_entry *entry, *prev;
466 unsigned long size = 0;
467
468 if (!symtab)
469 yasm_internal_error(N_("symtab is null"));
470
471 prev = NULL;
472 STAILQ_FOREACH(entry, symtab, qlink) {
473
474 yasm_intnum *size_intn=NULL, *value_intn=NULL;
475 bufp = buf;
476
477 /* get size (if specified); expr overrides stored integer */
478 if (entry->xsize) {
479 size_intn = yasm_intnum_copy(
480 yasm_expr_get_intnum(&entry->xsize, 1));
481 if (!size_intn) {
482 yasm_error_set(YASM_ERROR_VALUE,
483 N_("size specifier not an integer expression"));
484 yasm_errwarn_propagate(errwarns, entry->xsize->line);
485 }
486 }
487 else
488 size_intn = yasm_intnum_create_uint(entry->size);
489
490 /* get EQU value for constants */
491 if (entry->sym) {
492 const yasm_expr *equ_expr_c;
493 equ_expr_c = yasm_symrec_get_equ(entry->sym);
494
495 if (equ_expr_c != NULL) {
496 const yasm_intnum *equ_intn;
497 yasm_expr *equ_expr = yasm_expr_copy(equ_expr_c);
498 equ_intn = yasm_expr_get_intnum(&equ_expr, 1);
499
500 if (equ_intn == NULL) {
501 yasm_error_set(YASM_ERROR_VALUE,
502 N_("EQU value not an integer expression"));
503 yasm_errwarn_propagate(errwarns, equ_expr->line);
504 } else
505 value_intn = yasm_intnum_copy(equ_intn);
506 entry->index = SHN_ABS;
507 yasm_expr_destroy(equ_expr);
508 }
509 }
510 if (value_intn == NULL)
511 value_intn = yasm_intnum_create_uint(entry->value);
512
513 /* If symbol is in a TLS section, force its type to TLS. */
514 if (entry->sym) {
515 yasm_bytecode *precbc;
516 yasm_section *sect;
517 elf_secthead *shead;
518 if (yasm_symrec_get_label(entry->sym, &precbc) &&
519 (sect = yasm_bc_get_section(precbc)) &&
520 (shead = yasm_section_get_data(sect, &elf_section_data)) &&
521 shead->flags & SHF_TLS) {
522 entry->type = STT_TLS;
523 }
524 }
525
526 if (!elf_march->write_symtab_entry || !elf_march->symtab_entry_size)
527 yasm_internal_error(N_("Unsupported machine for ELF output"));
528 elf_march->write_symtab_entry(bufp, entry, value_intn, size_intn);
529 fwrite(buf, elf_march->symtab_entry_size, 1, f);
530 size += elf_march->symtab_entry_size;
531
532 yasm_intnum_destroy(size_intn);
533 yasm_intnum_destroy(value_intn);
534
535 prev = entry;
536 }
537 return size;
538 }
539
elf_symtab_set_nonzero(elf_symtab_entry * entry,yasm_section * sect,elf_section_index sectidx,elf_symbol_binding bind,elf_symbol_type type,yasm_expr * xsize,elf_address * value)540 void elf_symtab_set_nonzero(elf_symtab_entry *entry,
541 yasm_section *sect,
542 elf_section_index sectidx,
543 elf_symbol_binding bind,
544 elf_symbol_type type,
545 yasm_expr *xsize,
546 elf_address *value)
547 {
548 if (!entry)
549 yasm_internal_error("NULL entry");
550 if (sect) entry->sect = sect;
551 if (sectidx) entry->index = sectidx;
552 if (bind) entry->bind = bind;
553 if (type) entry->type = type;
554 if (xsize) entry->xsize = xsize;
555 if (value) entry->value = *value;
556 }
557
558 void
elf_sym_set_visibility(elf_symtab_entry * entry,elf_symbol_vis vis)559 elf_sym_set_visibility(elf_symtab_entry *entry,
560 elf_symbol_vis vis)
561 {
562 entry->vis = ELF_ST_VISIBILITY(vis);
563 }
564
565 void
elf_sym_set_type(elf_symtab_entry * entry,elf_symbol_type type)566 elf_sym_set_type(elf_symtab_entry *entry,
567 elf_symbol_type type)
568 {
569 entry->type = type;
570 }
571
572 void
elf_sym_set_size(elf_symtab_entry * entry,struct yasm_expr * size)573 elf_sym_set_size(elf_symtab_entry *entry,
574 struct yasm_expr *size)
575 {
576 if (entry->xsize)
577 yasm_expr_destroy(entry->xsize);
578 entry->xsize = size;
579 }
580
581 int
elf_sym_in_table(elf_symtab_entry * entry)582 elf_sym_in_table(elf_symtab_entry *entry)
583 {
584 return entry->in_table;
585 }
586
587 elf_secthead *
elf_secthead_create(elf_strtab_entry * name,elf_section_type type,elf_section_flags flags,elf_address offset,elf_size size)588 elf_secthead_create(elf_strtab_entry *name,
589 elf_section_type type,
590 elf_section_flags flags,
591 elf_address offset,
592 elf_size size)
593 {
594 elf_secthead *esd = yasm_xmalloc(sizeof(elf_secthead));
595
596 esd->type = type;
597 esd->flags = flags;
598 esd->offset = offset;
599 esd->size = yasm_intnum_create_uint(size);
600 esd->link = 0;
601 esd->info = 0;
602 esd->align = 0;
603 esd->entsize = 0;
604 esd->index = 0;
605
606 esd->sym = NULL;
607 esd->name = name;
608 esd->index = 0;
609 esd->rel_name = NULL;
610 esd->rel_index = 0;
611 esd->rel_offset = 0;
612 esd->nreloc = 0;
613
614 if (name && (strcmp(name->str, ".symtab") == 0)) {
615 if (!elf_march->symtab_entry_size || !elf_march->symtab_entry_align)
616 yasm_internal_error(N_("unsupported ELF format"));
617 esd->entsize = elf_march->symtab_entry_size;
618 esd->align = elf_march->symtab_entry_align;
619 }
620
621 return esd;
622 }
623
624 void
elf_secthead_destroy(elf_secthead * shead)625 elf_secthead_destroy(elf_secthead *shead)
626 {
627 if (shead == NULL)
628 yasm_internal_error(N_("shead is null"));
629
630 yasm_intnum_destroy(shead->size);
631
632 yasm_xfree(shead);
633 }
634
635 static void
elf_section_data_destroy(void * data)636 elf_section_data_destroy(void *data)
637 {
638 elf_secthead_destroy((elf_secthead *)data);
639 }
640
641 static void
elf_secthead_print(void * data,FILE * f,int indent_level)642 elf_secthead_print(void *data, FILE *f, int indent_level)
643 {
644 elf_secthead *sect = data;
645 fprintf(f, "%*sname=%s\n", indent_level, "",
646 sect->name ? sect->name->str : "<undef>");
647 fprintf(f, "%*ssym=\n", indent_level, "");
648 yasm_symrec_print(sect->sym, f, indent_level+1);
649 fprintf(f, "%*sindex=0x%x\n", indent_level, "", sect->index);
650 fprintf(f, "%*sflags=", indent_level, "");
651 if (sect->flags & SHF_WRITE)
652 fprintf(f, "WRITE ");
653 if (sect->flags & SHF_ALLOC)
654 fprintf(f, "ALLOC ");
655 if (sect->flags & SHF_EXECINSTR)
656 fprintf(f, "EXEC ");
657 /*if (sect->flags & SHF_MASKPROC)
658 fprintf(f, "PROC-SPECIFIC"); */
659 fprintf(f, "%*soffset=0x%lx\n", indent_level, "", sect->offset);
660 fprintf(f, "%*ssize=0x%lx\n", indent_level, "",
661 yasm_intnum_get_uint(sect->size));
662 fprintf(f, "%*slink=0x%x\n", indent_level, "", sect->link);
663 fprintf(f, "%*salign=%lu\n", indent_level, "", sect->align);
664 fprintf(f, "%*snreloc=%ld\n", indent_level, "", sect->nreloc);
665 }
666
667 unsigned long
elf_secthead_write_to_file(FILE * f,elf_secthead * shead,elf_section_index sindex)668 elf_secthead_write_to_file(FILE *f, elf_secthead *shead,
669 elf_section_index sindex)
670 {
671 unsigned char buf[SHDR_MAXSIZE], *bufp = buf;
672 shead->index = sindex;
673
674 if (shead == NULL)
675 yasm_internal_error("shead is null");
676
677 if (!elf_march->write_secthead || !elf_march->secthead_size)
678 yasm_internal_error(N_("Unsupported machine for ELF output"));
679 elf_march->write_secthead(bufp, shead);
680 if (fwrite(buf, elf_march->secthead_size, 1, f))
681 return elf_march->secthead_size;
682 yasm_internal_error(N_("Failed to write an elf section header"));
683 return 0;
684 }
685
686 void
elf_secthead_append_reloc(yasm_section * sect,elf_secthead * shead,elf_reloc_entry * reloc)687 elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead,
688 elf_reloc_entry *reloc)
689 {
690 if (sect == NULL)
691 yasm_internal_error("sect is null");
692 if (shead == NULL)
693 yasm_internal_error("shead is null");
694 if (reloc == NULL)
695 yasm_internal_error("reloc is null");
696
697 shead->nreloc++;
698 yasm_section_add_reloc(sect, (yasm_reloc *)reloc, elf_reloc_entry_destroy);
699 }
700
701 char *
elf_secthead_name_reloc_section(const char * basesect)702 elf_secthead_name_reloc_section(const char *basesect)
703 {
704 if (!elf_march->reloc_section_prefix)
705 {
706 yasm_internal_error(N_("Unsupported machine for ELF output"));
707 return NULL;
708 }
709 else
710 {
711 size_t prepend_length = strlen(elf_march->reloc_section_prefix);
712 char *sectname = yasm_xmalloc(prepend_length + strlen(basesect) + 1);
713 strcpy(sectname, elf_march->reloc_section_prefix);
714 strcat(sectname, basesect);
715 return sectname;
716 }
717 }
718
719 void
elf_handle_reloc_addend(yasm_intnum * intn,elf_reloc_entry * reloc,unsigned long offset)720 elf_handle_reloc_addend(yasm_intnum *intn,
721 elf_reloc_entry *reloc,
722 unsigned long offset)
723 {
724 if (!elf_march->handle_reloc_addend)
725 yasm_internal_error(N_("Unsupported machine for ELF output"));
726 elf_march->handle_reloc_addend(intn, reloc, offset);
727 }
728
729 unsigned long
elf_secthead_write_rel_to_file(FILE * f,elf_section_index symtab_idx,yasm_section * sect,elf_secthead * shead,elf_section_index sindex)730 elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab_idx,
731 yasm_section *sect, elf_secthead *shead,
732 elf_section_index sindex)
733 {
734 unsigned char buf[SHDR_MAXSIZE], *bufp = buf;
735
736 if (shead == NULL)
737 yasm_internal_error("shead is null");
738
739 if (!yasm_section_relocs_first(sect))
740 return 0; /* no relocations, no .rel.* section header */
741
742 shead->rel_index = sindex;
743
744 if (!elf_march->write_secthead_rel || !elf_march->secthead_size)
745 yasm_internal_error(N_("Unsupported machine for ELF output"));
746 elf_march->write_secthead_rel(bufp, shead, symtab_idx, sindex);
747 if (fwrite(buf, elf_march->secthead_size, 1, f))
748 return elf_march->secthead_size;
749 yasm_internal_error(N_("Failed to write an elf section header"));
750 return 0;
751 }
752
753 unsigned long
elf_secthead_write_relocs_to_file(FILE * f,yasm_section * sect,elf_secthead * shead,yasm_errwarns * errwarns)754 elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect,
755 elf_secthead *shead, yasm_errwarns *errwarns)
756 {
757 elf_reloc_entry *reloc;
758 unsigned char buf[RELOC_MAXSIZE], *bufp;
759 unsigned long size = 0;
760 long pos;
761
762 if (shead == NULL)
763 yasm_internal_error("shead is null");
764
765 reloc = (elf_reloc_entry *)yasm_section_relocs_first(sect);
766 if (!reloc)
767 return 0;
768
769 /* first align section to multiple of 4 */
770 pos = ftell(f);
771 if (pos == -1) {
772 yasm_error_set(YASM_ERROR_IO,
773 N_("couldn't read position on output stream"));
774 yasm_errwarn_propagate(errwarns, 0);
775 }
776 pos = (pos + 3) & ~3;
777 if (fseek(f, pos, SEEK_SET) < 0) {
778 yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream"));
779 yasm_errwarn_propagate(errwarns, 0);
780 }
781 shead->rel_offset = (unsigned long)pos;
782
783
784 while (reloc) {
785 yasm_sym_vis vis;
786 unsigned int r_type=0, r_sym;
787 elf_symtab_entry *esym;
788
789 esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
790 if (esym)
791 r_sym = esym->symindex;
792 else
793 r_sym = STN_UNDEF;
794
795 vis = yasm_symrec_get_visibility(reloc->reloc.sym);
796 if (!elf_march->map_reloc_info_to_type)
797 yasm_internal_error(N_("Unsupported arch/machine for elf output"));
798 r_type = elf_march->map_reloc_info_to_type(reloc);
799
800 bufp = buf;
801 if (!elf_march->write_reloc || !elf_march->reloc_entry_size)
802 yasm_internal_error(N_("Unsupported arch/machine for elf output"));
803 elf_march->write_reloc(bufp, reloc, r_type, r_sym);
804 fwrite(buf, elf_march->reloc_entry_size, 1, f);
805 size += elf_march->reloc_entry_size;
806
807 reloc = (elf_reloc_entry *)
808 yasm_section_reloc_next((yasm_reloc *)reloc);
809 }
810 return size;
811 }
812
813 elf_section_type
elf_secthead_get_type(elf_secthead * shead)814 elf_secthead_get_type(elf_secthead *shead)
815 {
816 return shead->type;
817 }
818
819 void
elf_secthead_set_typeflags(elf_secthead * shead,elf_section_type type,elf_section_flags flags)820 elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type,
821 elf_section_flags flags)
822 {
823 shead->type = type;
824 shead->flags = flags;
825 }
826
827 int
elf_secthead_is_empty(elf_secthead * shead)828 elf_secthead_is_empty(elf_secthead *shead)
829 {
830 return yasm_intnum_is_zero(shead->size);
831 }
832
833 yasm_symrec *
elf_secthead_get_sym(elf_secthead * shead)834 elf_secthead_get_sym(elf_secthead *shead)
835 {
836 return shead->sym;
837 }
838
839 elf_section_index
elf_secthead_get_index(elf_secthead * shead)840 elf_secthead_get_index(elf_secthead *shead)
841 {
842 return shead->index;
843 }
844
845 unsigned long
elf_secthead_get_align(const elf_secthead * shead)846 elf_secthead_get_align(const elf_secthead *shead)
847 {
848 return shead->align;
849 }
850
851 unsigned long
elf_secthead_set_align(elf_secthead * shead,unsigned long align)852 elf_secthead_set_align(elf_secthead *shead, unsigned long align)
853 {
854 return shead->align = align;
855 }
856
857 elf_section_info
elf_secthead_set_info(elf_secthead * shead,elf_section_info info)858 elf_secthead_set_info(elf_secthead *shead, elf_section_info info)
859 {
860 return shead->info = info;
861 }
862
863 elf_section_index
elf_secthead_set_index(elf_secthead * shead,elf_section_index sectidx)864 elf_secthead_set_index(elf_secthead *shead, elf_section_index sectidx)
865 {
866 return shead->index = sectidx;
867 }
868
869 elf_section_index
elf_secthead_set_link(elf_secthead * shead,elf_section_index link)870 elf_secthead_set_link(elf_secthead *shead, elf_section_index link)
871 {
872 return shead->link = link;
873 }
874
875 elf_section_index
elf_secthead_set_rel_index(elf_secthead * shead,elf_section_index sectidx)876 elf_secthead_set_rel_index(elf_secthead *shead, elf_section_index sectidx)
877 {
878 return shead->rel_index = sectidx;
879 }
880
881 elf_strtab_entry *
elf_secthead_set_rel_name(elf_secthead * shead,elf_strtab_entry * entry)882 elf_secthead_set_rel_name(elf_secthead *shead, elf_strtab_entry *entry)
883 {
884 return shead->rel_name = entry;
885 }
886
887 elf_size
elf_secthead_set_entsize(elf_secthead * shead,elf_size size)888 elf_secthead_set_entsize(elf_secthead *shead, elf_size size)
889 {
890 return shead->entsize = size;
891 }
892
893 yasm_symrec *
elf_secthead_set_sym(elf_secthead * shead,yasm_symrec * sym)894 elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym)
895 {
896 return shead->sym = sym;
897 }
898
899 void
elf_secthead_add_size(elf_secthead * shead,yasm_intnum * size)900 elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size)
901 {
902 if (size) {
903 yasm_intnum_calc(shead->size, YASM_EXPR_ADD, size);
904 }
905 }
906
907 long
elf_secthead_set_file_offset(elf_secthead * shead,long pos)908 elf_secthead_set_file_offset(elf_secthead *shead, long pos)
909 {
910 unsigned long align = shead->align;
911
912 if (align == 0 || align == 1) {
913 shead->offset = (unsigned long)pos;
914 return pos;
915 }
916 else if (align & (align - 1))
917 yasm_internal_error(
918 N_("alignment %d for section `%s' is not a power of 2"));
919 /*, align, sect->name->str);*/
920
921 shead->offset = (unsigned long)((pos + align - 1) & ~(align - 1));
922 return (long)shead->offset;
923 }
924
925 unsigned long
elf_proghead_get_size(void)926 elf_proghead_get_size(void)
927 {
928 if (!elf_march->proghead_size)
929 yasm_internal_error(N_("Unsupported ELF format for output"));
930 return elf_march->proghead_size;
931 }
932
933 unsigned long
elf_proghead_write_to_file(FILE * f,elf_offset secthead_addr,unsigned long secthead_count,elf_section_index shstrtab_index)934 elf_proghead_write_to_file(FILE *f,
935 elf_offset secthead_addr,
936 unsigned long secthead_count,
937 elf_section_index shstrtab_index)
938 {
939 unsigned char buf[EHDR_MAXSIZE], *bufp = buf;
940
941 YASM_WRITE_8(bufp, ELFMAG0); /* ELF magic number */
942 YASM_WRITE_8(bufp, ELFMAG1);
943 YASM_WRITE_8(bufp, ELFMAG2);
944 YASM_WRITE_8(bufp, ELFMAG3);
945
946 if (!elf_march->write_proghead || !elf_march->proghead_size)
947 yasm_internal_error(N_("Unsupported ELF format for output"));
948 elf_march->write_proghead(&bufp, secthead_addr, secthead_count, shstrtab_index);
949
950 if (((unsigned)(bufp - buf)) != elf_march->proghead_size)
951 yasm_internal_error(N_("ELF program header is not proper length"));
952
953 if (fwrite(buf, elf_march->proghead_size, 1, f))
954 return elf_march->proghead_size;
955
956 yasm_internal_error(N_("Failed to write ELF program header"));
957 return 0;
958 }
959