123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960 |
- /*
- * ELF object format helpers
- *
- * Copyright (C) 2003-2007 Michael Urman
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
- #include <util.h>
- #include <libyasm.h>
- #define YASM_OBJFMT_ELF_INTERNAL
- #include "elf.h"
- #include "elf-machine.h"
- static void elf_section_data_destroy(void *data);
- static void elf_secthead_print(void *data, FILE *f, int indent_level);
- const yasm_assoc_data_callback elf_section_data = {
- elf_section_data_destroy,
- elf_secthead_print
- };
- static void elf_symrec_data_destroy(/*@only@*/ void *d);
- static void elf_symtab_entry_print(void *data, FILE *f, int indent_level);
- static void elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level);
- const yasm_assoc_data_callback elf_symrec_data = {
- elf_symrec_data_destroy,
- elf_symtab_entry_print
- };
- const yasm_assoc_data_callback elf_ssym_symrec_data = {
- elf_symrec_data_destroy,
- elf_ssym_symtab_entry_print
- };
- extern elf_machine_handler
- elf_machine_handler_x86_x86,
- elf_machine_handler_x86_amd64,
- elf_machine_handler_x86_x32;
- static const elf_machine_handler *elf_machine_handlers[] =
- {
- &elf_machine_handler_x86_x86,
- &elf_machine_handler_x86_amd64,
- &elf_machine_handler_x86_x32,
- NULL
- };
- static const elf_machine_handler elf_null_machine = {0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0};
- static elf_machine_handler const *elf_march = &elf_null_machine;
- static yasm_symrec **elf_ssyms;
- const elf_machine_handler *
- elf_set_arch(yasm_arch *arch, yasm_symtab *symtab, int bits_pref)
- {
- const char *machine = yasm_arch_get_machine(arch);
- int i;
- for (i=0, elf_march = elf_machine_handlers[0];
- elf_march != NULL;
- elf_march = elf_machine_handlers[++i])
- {
- if (yasm__strcasecmp(yasm_arch_keyword(arch), elf_march->arch)==0) {
- if (yasm__strcasecmp(machine, elf_march->machine)==0) {
- if (bits_pref == 0 || bits_pref == elf_march->bits)
- break;
- } else if (bits_pref == elf_march->bits
- && yasm__strcasecmp(machine, "amd64") == 0
- && yasm__strcasecmp(elf_march->machine, "x32") == 0)
- break;
- }
- }
- if (elf_march && elf_march->num_ssyms > 0)
- {
- /* Allocate "special" syms */
- elf_ssyms =
- yasm_xmalloc(elf_march->num_ssyms * sizeof(yasm_symrec *));
- for (i=0; (unsigned int)i<elf_march->num_ssyms; i++)
- {
- /* FIXME: misuse of NULL bytecode */
- elf_ssyms[i] = yasm_symtab_define_label(symtab,
- elf_march->ssyms[i].name,
- NULL, 0, 0);
- yasm_symrec_add_data(elf_ssyms[i], &elf_ssym_symrec_data,
- (void*)&elf_march->ssyms[i]);
- }
- }
- return elf_march;
- }
- yasm_symrec *
- elf_get_special_sym(const char *name, const char *parser)
- {
- int i;
- for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
- if (yasm__strcasecmp(name, elf_march->ssyms[i].name) == 0)
- return elf_ssyms[i];
- }
- return NULL;
- }
- /* reloc functions */
- int elf_ssym_has_flag(yasm_symrec *wrt, int flag);
- int
- elf_is_wrt_sym_relative(yasm_symrec *wrt)
- {
- return elf_ssym_has_flag(wrt, ELF_SSYM_SYM_RELATIVE);
- }
- int
- elf_is_wrt_pos_adjusted(yasm_symrec *wrt)
- {
- return elf_ssym_has_flag(wrt, ELF_SSYM_CURPOS_ADJUST);
- }
- int
- elf_ssym_has_flag(yasm_symrec *wrt, int flag)
- {
- int i;
- for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
- if (elf_ssyms[i] == wrt)
- return (elf_march->ssyms[i].sym_rel & flag) != 0;
- }
- return 0;
- }
- /* takes ownership of addr */
- 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)
- {
- elf_reloc_entry *entry;
- if (!elf_march->accepts_reloc)
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- if (!elf_march->accepts_reloc(valsize, wrt))
- {
- if (addr)
- yasm_intnum_destroy(addr);
- return NULL;
- }
- if (sym == NULL)
- yasm_internal_error("sym is null");
- entry = yasm_xmalloc(sizeof(elf_reloc_entry));
- entry->reloc.sym = sym;
- entry->reloc.addr = addr;
- entry->rtype_rel = rel;
- entry->valsize = valsize;
- entry->addend = NULL;
- entry->wrt = wrt;
- entry->is_GOT_sym = is_GOT_sym;
- return entry;
- }
- void
- elf_reloc_entry_destroy(void *entry)
- {
- if (((elf_reloc_entry*)entry)->addend)
- yasm_intnum_destroy(((elf_reloc_entry*)entry)->addend);
- yasm_xfree(entry);
- }
- /* strtab functions */
- elf_strtab_entry *
- elf_strtab_entry_create(const char *str)
- {
- elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry));
- entry->str = yasm__xstrdup(str);
- entry->index = 0;
- return entry;
- }
- void
- elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str)
- {
- elf_strtab_entry *last;
- if (entry->str)
- yasm_xfree(entry->str);
- entry->str = yasm__xstrdup(str);
- /* Update all following indices since string length probably changes */
- last = entry;
- entry = STAILQ_NEXT(last, qlink);
- while (entry) {
- entry->index = last->index + (unsigned long)strlen(last->str) + 1;
- last = entry;
- entry = STAILQ_NEXT(last, qlink);
- }
- }
- elf_strtab_head *
- elf_strtab_create()
- {
- elf_strtab_head *strtab = yasm_xmalloc(sizeof(elf_strtab_head));
- elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry));
- STAILQ_INIT(strtab);
- entry->index = 0;
- entry->str = yasm__xstrdup("");
- STAILQ_INSERT_TAIL(strtab, entry, qlink);
- return strtab;
- }
- elf_strtab_entry *
- elf_strtab_append_str(elf_strtab_head *strtab, const char *str)
- {
- elf_strtab_entry *last, *entry;
- if (strtab == NULL)
- yasm_internal_error("strtab is null");
- if (STAILQ_EMPTY(strtab))
- yasm_internal_error("strtab is missing initial dummy entry");
- last = STAILQ_LAST(strtab, elf_strtab_entry, qlink);
- entry = elf_strtab_entry_create(str);
- entry->index = last->index + (unsigned long)strlen(last->str) + 1;
- STAILQ_INSERT_TAIL(strtab, entry, qlink);
- return entry;
- }
- void
- elf_strtab_destroy(elf_strtab_head *strtab)
- {
- elf_strtab_entry *s1, *s2;
- if (strtab == NULL)
- yasm_internal_error("strtab is null");
- if (STAILQ_EMPTY(strtab))
- yasm_internal_error("strtab is missing initial dummy entry");
- s1 = STAILQ_FIRST(strtab);
- while (s1 != NULL) {
- s2 = STAILQ_NEXT(s1, qlink);
- yasm_xfree(s1->str);
- yasm_xfree(s1);
- s1 = s2;
- }
- yasm_xfree(strtab);
- }
- unsigned long
- elf_strtab_output_to_file(FILE *f, elf_strtab_head *strtab)
- {
- unsigned long size = 0;
- elf_strtab_entry *entry;
- if (strtab == NULL)
- yasm_internal_error("strtab is null");
- /* consider optimizing tables here */
- STAILQ_FOREACH(entry, strtab, qlink) {
- size_t len = 1 + strlen(entry->str);
- fwrite(entry->str, len, 1, f);
- size += (unsigned long)len;
- }
- return size;
- }
- /* symtab functions */
- elf_symtab_entry *
- elf_symtab_entry_create(elf_strtab_entry *name,
- yasm_symrec *sym)
- {
- elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry));
- entry->in_table = 0;
- entry->sym = sym;
- entry->sect = NULL;
- entry->name = name;
- entry->value = 0;
- entry->xsize = NULL;
- entry->size = 0;
- entry->index = 0;
- entry->bind = 0;
- entry->type = STT_NOTYPE;
- entry->vis = STV_DEFAULT;
- return entry;
- }
- static void
- elf_symtab_entry_destroy(elf_symtab_entry *entry)
- {
- if (entry == NULL)
- yasm_internal_error("symtab entry is null");
- yasm_xfree(entry);
- }
- static void
- elf_symrec_data_destroy(void *data)
- {
- /* do nothing, as this stuff is in the symtab anyway... this speaks of bad
- * design/use or this stuff, i fear */
- /* watch for double-free here ... */
- /*elf_symtab_entry_destroy((elf_symtab_entry *)data);*/
- }
- static void
- elf_symtab_entry_print(void *data, FILE *f, int indent_level)
- {
- elf_symtab_entry *entry = data;
- if (entry == NULL)
- yasm_internal_error("symtab entry is null");
- fprintf(f, "%*sbind=", indent_level, "");
- switch (entry->bind) {
- case STB_LOCAL: fprintf(f, "local\n"); break;
- case STB_GLOBAL: fprintf(f, "global\n"); break;
- case STB_WEAK: fprintf(f, "weak\n"); break;
- default: fprintf(f, "undef\n"); break;
- }
- fprintf(f, "%*stype=", indent_level, "");
- switch (entry->type) {
- case STT_NOTYPE: fprintf(f, "notype\n"); break;
- case STT_OBJECT: fprintf(f, "object\n"); break;
- case STT_FUNC: fprintf(f, "func\n"); break;
- case STT_SECTION: fprintf(f, "section\n");break;
- case STT_FILE: fprintf(f, "file\n"); break;
- default: fprintf(f, "undef\n"); break;
- }
- fprintf(f, "%*ssize=", indent_level, "");
- if (entry->xsize)
- yasm_expr_print(entry->xsize, f);
- else
- fprintf(f, "%ld", entry->size);
- fprintf(f, "\n");
- }
- static void
- elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level)
- {
- /* TODO */
- }
- elf_symtab_head *
- elf_symtab_create()
- {
- elf_symtab_head *symtab = yasm_xmalloc(sizeof(elf_symtab_head));
- elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry));
- STAILQ_INIT(symtab);
- entry->in_table = 1;
- entry->sym = NULL;
- entry->sect = NULL;
- entry->name = NULL;
- entry->value = 0;
- entry->xsize = NULL;
- entry->size = 0;
- entry->index = SHN_UNDEF;
- entry->bind = STB_LOCAL;
- entry->type = STT_NOTYPE;
- entry->vis = STV_DEFAULT;
- entry->symindex = 0;
- STAILQ_INSERT_TAIL(symtab, entry, qlink);
- return symtab;
- }
- void
- elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry)
- {
- if (symtab == NULL)
- yasm_internal_error("symtab is null");
- if (entry == NULL)
- yasm_internal_error("symtab entry is null");
- if (STAILQ_EMPTY(symtab))
- yasm_internal_error(N_("symtab is missing initial dummy entry"));
- STAILQ_INSERT_TAIL(symtab, entry, qlink);
- entry->in_table = 1;
- }
- void
- elf_symtab_insert_local_sym(elf_symtab_head *symtab, elf_symtab_entry *entry)
- {
- elf_symtab_entry *after = STAILQ_FIRST(symtab);
- elf_symtab_entry *before = NULL;
- while (after && (after->bind == STB_LOCAL)) {
- before = after;
- if (before->type == STT_FILE) break;
- after = STAILQ_NEXT(after, qlink);
- }
- STAILQ_INSERT_AFTER(symtab, before, entry, qlink);
- entry->in_table = 1;
- }
- void
- elf_symtab_destroy(elf_symtab_head *symtab)
- {
- elf_symtab_entry *s1, *s2;
- if (symtab == NULL)
- yasm_internal_error("symtab is null");
- if (STAILQ_EMPTY(symtab))
- yasm_internal_error(N_("symtab is missing initial dummy entry"));
- s1 = STAILQ_FIRST(symtab);
- while (s1 != NULL) {
- s2 = STAILQ_NEXT(s1, qlink);
- elf_symtab_entry_destroy(s1);
- s1 = s2;
- }
- yasm_xfree(symtab);
- }
- unsigned long
- elf_symtab_assign_indices(elf_symtab_head *symtab)
- {
- elf_symtab_entry *entry, *prev=NULL;
- unsigned long last_local=0;
- if (symtab == NULL)
- yasm_internal_error("symtab is null");
- if (STAILQ_EMPTY(symtab))
- yasm_internal_error(N_("symtab is missing initial dummy entry"));
- STAILQ_FOREACH(entry, symtab, qlink) {
- if (prev)
- entry->symindex = prev->symindex + 1;
- if (entry->bind == STB_LOCAL)
- last_local = entry->symindex;
- prev = entry;
- }
- return last_local + 1;
- }
- unsigned long
- elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab,
- yasm_errwarns *errwarns)
- {
- unsigned char buf[SYMTAB_MAXSIZE], *bufp;
- elf_symtab_entry *entry;
- unsigned long size = 0;
- if (!symtab)
- yasm_internal_error(N_("symtab is null"));
- STAILQ_FOREACH(entry, symtab, qlink) {
- yasm_intnum *size_intn=NULL, *value_intn=NULL;
- bufp = buf;
- /* get size (if specified); expr overrides stored integer */
- if (entry->xsize) {
- size_intn = yasm_intnum_copy(
- yasm_expr_get_intnum(&entry->xsize, 1));
- if (!size_intn) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("size specifier not an integer expression"));
- yasm_errwarn_propagate(errwarns, entry->xsize->line);
- }
- }
- else
- size_intn = yasm_intnum_create_uint(entry->size);
- /* get EQU value for constants */
- if (entry->sym) {
- const yasm_expr *equ_expr_c;
- equ_expr_c = yasm_symrec_get_equ(entry->sym);
- if (equ_expr_c != NULL) {
- const yasm_intnum *equ_intn;
- yasm_expr *equ_expr = yasm_expr_copy(equ_expr_c);
- equ_intn = yasm_expr_get_intnum(&equ_expr, 1);
- if (equ_intn == NULL) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("EQU value not an integer expression"));
- yasm_errwarn_propagate(errwarns, equ_expr->line);
- } else
- value_intn = yasm_intnum_copy(equ_intn);
- entry->index = SHN_ABS;
- yasm_expr_destroy(equ_expr);
- }
- }
- if (value_intn == NULL)
- value_intn = yasm_intnum_create_uint(entry->value);
- /* If symbol is in a TLS section, force its type to TLS. */
- if (entry->sym) {
- yasm_bytecode *precbc;
- yasm_section *sect;
- elf_secthead *shead;
- if (yasm_symrec_get_label(entry->sym, &precbc) &&
- (sect = yasm_bc_get_section(precbc)) &&
- (shead = yasm_section_get_data(sect, &elf_section_data)) &&
- shead->flags & SHF_TLS) {
- entry->type = STT_TLS;
- }
- }
- if (!elf_march->write_symtab_entry || !elf_march->symtab_entry_size)
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- elf_march->write_symtab_entry(bufp, entry, value_intn, size_intn);
- fwrite(buf, elf_march->symtab_entry_size, 1, f);
- size += elf_march->symtab_entry_size;
- yasm_intnum_destroy(size_intn);
- yasm_intnum_destroy(value_intn);
- }
- return size;
- }
- void 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)
- {
- if (!entry)
- yasm_internal_error("NULL entry");
- if (sect) entry->sect = sect;
- if (sectidx) entry->index = sectidx;
- if (bind) entry->bind = bind;
- if (type) entry->type = type;
- if (xsize) entry->xsize = xsize;
- if (value) entry->value = *value;
- }
- void
- elf_sym_set_visibility(elf_symtab_entry *entry,
- elf_symbol_vis vis)
- {
- entry->vis = ELF_ST_VISIBILITY(vis);
- }
- void
- elf_sym_set_type(elf_symtab_entry *entry,
- elf_symbol_type type)
- {
- entry->type = type;
- }
- void
- elf_sym_set_size(elf_symtab_entry *entry,
- struct yasm_expr *size)
- {
- if (entry->xsize)
- yasm_expr_destroy(entry->xsize);
- entry->xsize = size;
- }
- int
- elf_sym_in_table(elf_symtab_entry *entry)
- {
- return entry->in_table;
- }
- elf_secthead *
- elf_secthead_create(elf_strtab_entry *name,
- elf_section_type type,
- elf_section_flags flags,
- elf_address offset,
- elf_size size)
- {
- elf_secthead *esd = yasm_xmalloc(sizeof(elf_secthead));
- esd->type = type;
- esd->flags = flags;
- esd->offset = offset;
- esd->size = yasm_intnum_create_uint(size);
- esd->link = 0;
- esd->info = 0;
- esd->align = 0;
- esd->entsize = 0;
- esd->index = 0;
- esd->sym = NULL;
- esd->name = name;
- esd->index = 0;
- esd->rel_name = NULL;
- esd->rel_index = 0;
- esd->rel_offset = 0;
- esd->nreloc = 0;
- if (name && (strcmp(name->str, ".symtab") == 0)) {
- if (!elf_march->symtab_entry_size || !elf_march->symtab_entry_align)
- yasm_internal_error(N_("unsupported ELF format"));
- esd->entsize = elf_march->symtab_entry_size;
- esd->align = elf_march->symtab_entry_align;
- }
- return esd;
- }
- void
- elf_secthead_destroy(elf_secthead *shead)
- {
- if (shead == NULL)
- yasm_internal_error(N_("shead is null"));
- yasm_intnum_destroy(shead->size);
- yasm_xfree(shead);
- }
- static void
- elf_section_data_destroy(void *data)
- {
- elf_secthead_destroy((elf_secthead *)data);
- }
- static void
- elf_secthead_print(void *data, FILE *f, int indent_level)
- {
- elf_secthead *sect = data;
- fprintf(f, "%*sname=%s\n", indent_level, "",
- sect->name ? sect->name->str : "<undef>");
- fprintf(f, "%*ssym=\n", indent_level, "");
- yasm_symrec_print(sect->sym, f, indent_level+1);
- fprintf(f, "%*sindex=0x%x\n", indent_level, "", sect->index);
- fprintf(f, "%*sflags=", indent_level, "");
- if (sect->flags & SHF_WRITE)
- fprintf(f, "WRITE ");
- if (sect->flags & SHF_ALLOC)
- fprintf(f, "ALLOC ");
- if (sect->flags & SHF_EXECINSTR)
- fprintf(f, "EXEC ");
- /*if (sect->flags & SHF_MASKPROC)
- fprintf(f, "PROC-SPECIFIC"); */
- fprintf(f, "%*soffset=0x%lx\n", indent_level, "", sect->offset);
- fprintf(f, "%*ssize=0x%lx\n", indent_level, "",
- yasm_intnum_get_uint(sect->size));
- fprintf(f, "%*slink=0x%x\n", indent_level, "", sect->link);
- fprintf(f, "%*salign=%lu\n", indent_level, "", sect->align);
- fprintf(f, "%*snreloc=%ld\n", indent_level, "", sect->nreloc);
- }
- unsigned long
- elf_secthead_write_to_file(FILE *f, elf_secthead *shead,
- elf_section_index sindex)
- {
- unsigned char buf[SHDR_MAXSIZE], *bufp = buf;
- shead->index = sindex;
- if (shead == NULL)
- yasm_internal_error("shead is null");
- if (!elf_march->write_secthead || !elf_march->secthead_size)
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- elf_march->write_secthead(bufp, shead);
- if (fwrite(buf, elf_march->secthead_size, 1, f))
- return elf_march->secthead_size;
- yasm_internal_error(N_("Failed to write an elf section header"));
- return 0;
- }
- void
- elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead,
- elf_reloc_entry *reloc)
- {
- if (sect == NULL)
- yasm_internal_error("sect is null");
- if (shead == NULL)
- yasm_internal_error("shead is null");
- if (reloc == NULL)
- yasm_internal_error("reloc is null");
- shead->nreloc++;
- yasm_section_add_reloc(sect, (yasm_reloc *)reloc, elf_reloc_entry_destroy);
- }
- char *
- elf_secthead_name_reloc_section(const char *basesect)
- {
- if (!elf_march->reloc_section_prefix)
- {
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- return NULL;
- }
- else
- {
- size_t prepend_length = strlen(elf_march->reloc_section_prefix);
- char *sectname = yasm_xmalloc(prepend_length + strlen(basesect) + 1);
- strcpy(sectname, elf_march->reloc_section_prefix);
- strcat(sectname, basesect);
- return sectname;
- }
- }
- void
- elf_handle_reloc_addend(yasm_intnum *intn,
- elf_reloc_entry *reloc,
- unsigned long offset)
- {
- if (!elf_march->handle_reloc_addend)
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- elf_march->handle_reloc_addend(intn, reloc, offset);
- }
- 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)
- {
- unsigned char buf[SHDR_MAXSIZE], *bufp = buf;
- if (shead == NULL)
- yasm_internal_error("shead is null");
- if (!yasm_section_relocs_first(sect))
- return 0; /* no relocations, no .rel.* section header */
- shead->rel_index = sindex;
- if (!elf_march->write_secthead_rel || !elf_march->secthead_size)
- yasm_internal_error(N_("Unsupported machine for ELF output"));
- elf_march->write_secthead_rel(bufp, shead, symtab_idx, sindex);
- if (fwrite(buf, elf_march->secthead_size, 1, f))
- return elf_march->secthead_size;
- yasm_internal_error(N_("Failed to write an elf section header"));
- return 0;
- }
- unsigned long
- elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect,
- elf_secthead *shead, yasm_errwarns *errwarns)
- {
- elf_reloc_entry *reloc;
- unsigned char buf[RELOC_MAXSIZE], *bufp;
- unsigned long size = 0;
- long pos;
- if (shead == NULL)
- yasm_internal_error("shead is null");
- reloc = (elf_reloc_entry *)yasm_section_relocs_first(sect);
- if (!reloc)
- return 0;
- /* first align section to multiple of 4 */
- pos = ftell(f);
- if (pos == -1) {
- yasm_error_set(YASM_ERROR_IO,
- N_("couldn't read position on output stream"));
- yasm_errwarn_propagate(errwarns, 0);
- }
- pos = (pos + 3) & ~3;
- if (fseek(f, pos, SEEK_SET) < 0) {
- yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream"));
- yasm_errwarn_propagate(errwarns, 0);
- }
- shead->rel_offset = (unsigned long)pos;
- while (reloc) {
- unsigned int r_type=0, r_sym;
- elf_symtab_entry *esym;
- esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
- if (esym)
- r_sym = esym->symindex;
- else
- r_sym = STN_UNDEF;
- if (!elf_march->map_reloc_info_to_type)
- yasm_internal_error(N_("Unsupported arch/machine for elf output"));
- r_type = elf_march->map_reloc_info_to_type(reloc);
- bufp = buf;
- if (!elf_march->write_reloc || !elf_march->reloc_entry_size)
- yasm_internal_error(N_("Unsupported arch/machine for elf output"));
- elf_march->write_reloc(bufp, reloc, r_type, r_sym);
- fwrite(buf, elf_march->reloc_entry_size, 1, f);
- size += elf_march->reloc_entry_size;
- reloc = (elf_reloc_entry *)
- yasm_section_reloc_next((yasm_reloc *)reloc);
- }
- return size;
- }
- elf_section_type
- elf_secthead_get_type(elf_secthead *shead)
- {
- return shead->type;
- }
- void
- elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type,
- elf_section_flags flags)
- {
- shead->type = type;
- shead->flags = flags;
- }
- int
- elf_secthead_is_empty(elf_secthead *shead)
- {
- return yasm_intnum_is_zero(shead->size);
- }
- yasm_symrec *
- elf_secthead_get_sym(elf_secthead *shead)
- {
- return shead->sym;
- }
- elf_section_index
- elf_secthead_get_index(elf_secthead *shead)
- {
- return shead->index;
- }
- unsigned long
- elf_secthead_get_align(const elf_secthead *shead)
- {
- return shead->align;
- }
- unsigned long
- elf_secthead_set_align(elf_secthead *shead, unsigned long align)
- {
- return shead->align = align;
- }
- elf_section_info
- elf_secthead_set_info(elf_secthead *shead, elf_section_info info)
- {
- return shead->info = info;
- }
- elf_section_index
- elf_secthead_set_index(elf_secthead *shead, elf_section_index sectidx)
- {
- return shead->index = sectidx;
- }
- elf_section_index
- elf_secthead_set_link(elf_secthead *shead, elf_section_index link)
- {
- return shead->link = link;
- }
- elf_section_index
- elf_secthead_set_rel_index(elf_secthead *shead, elf_section_index sectidx)
- {
- return shead->rel_index = sectidx;
- }
- elf_strtab_entry *
- elf_secthead_set_rel_name(elf_secthead *shead, elf_strtab_entry *entry)
- {
- return shead->rel_name = entry;
- }
- elf_size
- elf_secthead_set_entsize(elf_secthead *shead, elf_size size)
- {
- return shead->entsize = size;
- }
- yasm_symrec *
- elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym)
- {
- return shead->sym = sym;
- }
- void
- elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size)
- {
- if (size) {
- yasm_intnum_calc(shead->size, YASM_EXPR_ADD, size);
- }
- }
- long
- elf_secthead_set_file_offset(elf_secthead *shead, long pos)
- {
- unsigned long align = shead->align;
- if (align == 0 || align == 1) {
- shead->offset = (unsigned long)pos;
- return pos;
- }
- else if (align & (align - 1))
- yasm_internal_error(
- N_("alignment %d for section `%s' is not a power of 2"));
- /*, align, sect->name->str);*/
- shead->offset = (unsigned long)((pos + align - 1) & ~(align - 1));
- return (long)shead->offset;
- }
- unsigned long
- elf_proghead_get_size(void)
- {
- if (!elf_march->proghead_size)
- yasm_internal_error(N_("Unsupported ELF format for output"));
- return elf_march->proghead_size;
- }
- unsigned long
- elf_proghead_write_to_file(FILE *f,
- elf_offset secthead_addr,
- unsigned long secthead_count,
- elf_section_index shstrtab_index)
- {
- unsigned char buf[EHDR_MAXSIZE], *bufp = buf;
- YASM_WRITE_8(bufp, ELFMAG0); /* ELF magic number */
- YASM_WRITE_8(bufp, ELFMAG1);
- YASM_WRITE_8(bufp, ELFMAG2);
- YASM_WRITE_8(bufp, ELFMAG3);
- if (!elf_march->write_proghead || !elf_march->proghead_size)
- yasm_internal_error(N_("Unsupported ELF format for output"));
- elf_march->write_proghead(&bufp, secthead_addr, secthead_count, shstrtab_index);
- if (((unsigned)(bufp - buf)) != elf_march->proghead_size)
- yasm_internal_error(N_("ELF program header is not proper length"));
- if (fwrite(buf, elf_march->proghead_size, 1, f))
- return elf_march->proghead_size;
- yasm_internal_error(N_("Failed to write ELF program header"));
- return 0;
- }
|