12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403 |
- /*
- * ELF object format
- *
- * 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>
- /* Notes
- *
- * elf-objfmt uses the "linking" view of an ELF file:
- * ELF header, an optional program header table, several sections,
- * and a section header table
- *
- * The ELF header tells us some overall program information,
- * where to find the PHT (if it exists) with phnum and phentsize,
- * and where to find the SHT with shnum and shentsize
- *
- * The PHT doesn't seem to be generated by NASM for elftest.asm
- *
- * The SHT
- *
- * Each Section is spatially disjoint, and has exactly one SHT entry.
- */
- #include <libyasm.h>
- #include "elf.h"
- #include "elf-machine.h"
- typedef struct yasm_objfmt_elf {
- yasm_objfmt_base objfmt; /* base structure */
- elf_symtab_head* elf_symtab; /* symbol table of indexed syms */
- elf_strtab_head* shstrtab; /* section name strtab */
- elf_strtab_head* strtab; /* strtab entries */
- elf_strtab_entry *file_strtab_entry;/* .file symbol associated string */
- yasm_symrec *dotdotsym; /* ..sym symbol */
- } yasm_objfmt_elf;
- typedef struct {
- yasm_objfmt_elf *objfmt_elf;
- yasm_errwarns *errwarns;
- FILE *f;
- elf_secthead *shead;
- yasm_section *sect;
- yasm_object *object;
- unsigned long sindex;
- yasm_symrec *GOT_sym;
- } elf_objfmt_output_info;
- typedef struct {
- yasm_object *object;
- yasm_objfmt_elf *objfmt_elf;
- yasm_errwarns *errwarns;
- int local_names;
- } build_symtab_info;
- yasm_objfmt_module yasm_elf_LTX_objfmt;
- yasm_objfmt_module yasm_elf32_LTX_objfmt;
- yasm_objfmt_module yasm_elf64_LTX_objfmt;
- yasm_objfmt_module yasm_elfx32_LTX_objfmt;
- static elf_symtab_entry *
- elf_objfmt_symtab_append(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym,
- elf_section_index sectidx, elf_symbol_binding bind,
- elf_symbol_type type, elf_symbol_vis vis,
- yasm_expr *size, elf_address *value,
- yasm_object *object)
- {
- elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
- if (!entry) {
- /*@only@*/ char *symname = yasm_symrec_get_global_name(sym, object);
- elf_strtab_entry *name =
- elf_strtab_append_str(objfmt_elf->strtab, symname);
- yasm_xfree(symname);
- entry = elf_symtab_entry_create(name, sym);
- yasm_symrec_add_data(sym, &elf_symrec_data, entry);
- }
- /* Only append to table if not already appended */
- if (!elf_sym_in_table(entry))
- elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);
- elf_symtab_set_nonzero(entry, NULL, sectidx, bind, type, size, value);
- elf_sym_set_visibility(entry, vis);
- return entry;
- }
- static elf_symtab_entry *
- build_extern(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
- {
- yasm_valparamhead *objext_valparams =
- yasm_symrec_get_objext_valparams(sym);
- if (objext_valparams) {
- yasm_valparam *vp = yasm_vps_first(objext_valparams);
- for (; vp; vp = yasm_vps_next(vp)) {
- if (yasm_vp_string(vp))
- yasm_error_set(YASM_ERROR_TYPE,
- N_("unrecognized symbol type `%s'"),
- yasm_vp_string(vp));
- }
- }
- return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL, 0,
- STV_DEFAULT, NULL, NULL, object);
- }
- struct elf_build_global_data {
- yasm_expr *size;
- unsigned long type; /* elf_symbol_type */
- elf_symbol_vis vis;
- unsigned int vis_overrides;
- };
- static int
- elf_global_helper_valparam(void *obj, yasm_valparam *vp, unsigned long line,
- void *d)
- {
- struct elf_build_global_data *data = (struct elf_build_global_data *)d;
- const char *s;
- if (!vp->val && (s = yasm_vp_id(vp))) {
- yasm_error_set(YASM_ERROR_TYPE, N_("unrecognized symbol type `%s'"),
- s);
- return -1;
- } else if (!vp->val && vp->type == YASM_PARAM_EXPR && !data->size) {
- data->size = yasm_expr_copy(vp->param.e);
- return 0;
- } else
- return yasm_dir_helper_valparam_warn(obj, vp, line, d);
- }
- static int
- elf_global_helper_vis(void *obj, yasm_valparam *vp, unsigned long line,
- void *d, uintptr_t vis)
- {
- struct elf_build_global_data *data = (struct elf_build_global_data *)d;
- data->vis = vis;
- data->vis_overrides++;
- return 0;
- }
- static elf_symtab_entry *
- build_global(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
- {
- yasm_valparamhead *objext_valparams =
- yasm_symrec_get_objext_valparams(sym);
- struct elf_build_global_data data;
- static const yasm_dir_help help[] = {
- { "function", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_build_global_data, type), STT_FUNC },
- { "data", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_build_global_data, type), STT_OBJECT },
- { "object", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_build_global_data, type), STT_OBJECT },
- { "internal", 0, elf_global_helper_vis, 0, STV_INTERNAL },
- { "hidden", 0, elf_global_helper_vis, 0, STV_HIDDEN },
- { "protected", 0, elf_global_helper_vis, 0, STV_PROTECTED },
- };
- data.size = NULL;
- data.type = 0;
- data.vis = STV_DEFAULT;
- data.vis_overrides = 0;
- if (objext_valparams)
- yasm_dir_helper(sym, yasm_vps_first(objext_valparams),
- yasm_symrec_get_decl_line(sym), help, NELEMS(help),
- &data, elf_global_helper_valparam);
- if (data.vis_overrides > 1) {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("More than one symbol visibility provided; using last"));
- }
- return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL,
- data.type, data.vis, data.size, NULL,
- object);
- }
- static /*@null@*/ elf_symtab_entry *
- build_common(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
- {
- yasm_expr **size = yasm_symrec_get_common_size(sym);
- yasm_valparamhead *objext_valparams =
- yasm_symrec_get_objext_valparams(sym);
- unsigned long addralign = 0;
- if (objext_valparams) {
- yasm_valparam *vp = yasm_vps_first(objext_valparams);
- for (; vp; vp = yasm_vps_next(vp)) {
- if (!vp->val) {
- /*@only@*/ /*@null@*/ yasm_expr *align_expr;
- /*@dependent@*/ /*@null@*/ const yasm_intnum *align_intn;
- if (!(align_expr = yasm_vp_expr(vp, object->symtab,
- yasm_symrec_get_def_line(sym)))
- || !(align_intn = yasm_expr_get_intnum(&align_expr, 0))) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("alignment constraint is not an integer"));
- if (align_expr)
- yasm_expr_destroy(align_expr);
- return NULL;
- }
- addralign = yasm_intnum_get_uint(align_intn);
- yasm_expr_destroy(align_expr);
- /* Alignments must be a power of two. */
- if (!is_exp2(addralign)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("alignment constraint is not a power of two"));
- return NULL;
- }
- } else
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("Unrecognized qualifier `%s'"), vp->val);
- }
- }
- return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_COMMON, STB_GLOBAL,
- 0, STV_DEFAULT, *size, &addralign, object);
- }
- static int
- elf_objfmt_build_symtab(yasm_symrec *sym, /*@null@*/ void *d)
- {
- build_symtab_info *info = (build_symtab_info *)d;
- yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
- yasm_sym_status status = yasm_symrec_get_status(sym);
- elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
- elf_address value=0;
- yasm_section *sect=NULL;
- yasm_bytecode *precbc=NULL;
- assert(info != NULL);
- if (vis & YASM_SYM_EXTERN) {
- entry = build_extern(info->objfmt_elf, sym, info->object);
- yasm_errwarn_propagate(info->errwarns,
- yasm_symrec_get_decl_line(sym));
- return 0;
- }
- if (vis & YASM_SYM_COMMON) {
- entry = build_common(info->objfmt_elf, sym, info->object);
- yasm_errwarn_propagate(info->errwarns,
- yasm_symrec_get_decl_line(sym));
- /* If the COMMON variable was actually defined, fall through. */
- if (!(status & YASM_SYM_DEFINED))
- return 0;
- }
- /* Ignore any undefined at this point. */
- if (!(status & YASM_SYM_DEFINED))
- return 0;
- if (!yasm_symrec_get_label(sym, &precbc)) {
- if (!yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym))
- return 0;
- precbc = NULL;
- }
- if (precbc)
- sect = yasm_bc_get_section(precbc);
- if (entry && elf_sym_in_table(entry))
- ;
- else if (vis & YASM_SYM_GLOBAL) {
- entry = build_global(info->objfmt_elf, sym, info->object);
- yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
- } else {
- int is_sect = 0;
- /* Locals (except when debugging) do not need to be
- * in the symbol table, unless they're a section.
- */
- if (sect &&
- strcmp(yasm_symrec_get_name(sym), yasm_section_get_name(sect))==0)
- is_sect = 1;
- #if 0
- /* FIXME: to enable this we must have handling in place for special
- * symbols.
- */
- if (!info->local_names && !is_sect)
- return 0;
- #else
- if (yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym))
- return 0;
- #endif
- entry = yasm_symrec_get_data(sym, &elf_symrec_data);
- if (!entry) {
- /*@only@*/ char *symname =
- yasm_symrec_get_global_name(sym, info->object);
- elf_strtab_entry *name = !info->local_names || is_sect ? NULL :
- elf_strtab_append_str(info->objfmt_elf->strtab, symname);
- yasm_xfree(symname);
- entry = elf_symtab_entry_create(name, sym);
- yasm_symrec_add_data(sym, &elf_symrec_data, entry);
- }
- if (!elf_sym_in_table(entry))
- elf_symtab_insert_local_sym(info->objfmt_elf->elf_symtab, entry);
- elf_symtab_set_nonzero(entry, sect, 0, STB_LOCAL,
- is_sect ? STT_SECTION : 0, NULL, 0);
- if (is_sect)
- return 0;
- }
- if (precbc)
- value = yasm_bc_next_offset(precbc);
- elf_symtab_set_nonzero(entry, sect, 0, 0, 0, NULL, &value);
- return 0;
- }
- static yasm_objfmt *
- elf_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module,
- int bits_pref,
- const elf_machine_handler **elf_march_out)
- {
- yasm_objfmt_elf *objfmt_elf = yasm_xmalloc(sizeof(yasm_objfmt_elf));
- yasm_symrec *filesym;
- elf_symtab_entry *entry;
- const elf_machine_handler *elf_march;
- objfmt_elf->objfmt.module = module;
- elf_march = elf_set_arch(object->arch, object->symtab, bits_pref);
- if (!elf_march) {
- yasm_xfree(objfmt_elf);
- return NULL;
- }
- if (elf_march_out)
- *elf_march_out = elf_march;
- objfmt_elf->shstrtab = elf_strtab_create();
- objfmt_elf->strtab = elf_strtab_create();
- objfmt_elf->elf_symtab = elf_symtab_create();
- /* FIXME: misuse of NULL bytecode here; it works, but only barely. */
- filesym = yasm_symtab_define_label(object->symtab, ".file", NULL, 0, 0);
- if (!object->deb_filename) {
- object->deb_filename = yasm_replace_path(
- module->replace_map, module->replace_map_size,
- object->src_filename, strlen(object->src_filename));
- }
- /* Put in current input filename; we'll replace it in output() */
- objfmt_elf->file_strtab_entry =
- elf_strtab_append_str(objfmt_elf->strtab, object->deb_filename);
- entry = elf_symtab_entry_create(objfmt_elf->file_strtab_entry, filesym);
- yasm_symrec_add_data(filesym, &elf_symrec_data, entry);
- elf_symtab_set_nonzero(entry, NULL, SHN_ABS, STB_LOCAL, STT_FILE, NULL,
- NULL);
- elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);
- /* FIXME: misuse of NULL bytecode */
- objfmt_elf->dotdotsym =
- yasm_symtab_define_label(object->symtab, "..sym", NULL, 0, 0);
- return (yasm_objfmt *)objfmt_elf;
- }
- static yasm_objfmt *
- elf_objfmt_create(yasm_object *object)
- {
- const elf_machine_handler *elf_march;
- yasm_objfmt *objfmt;
- yasm_objfmt_elf *objfmt_elf;
- objfmt = elf_objfmt_create_common(object, &yasm_elf_LTX_objfmt, 0,
- &elf_march);
- if (objfmt) {
- objfmt_elf = (yasm_objfmt_elf *)objfmt;
- /* Figure out which bitness of object format to use */
- if (strcmp (elf_march->machine, "x32") == 0)
- objfmt_elf->objfmt.module = &yasm_elfx32_LTX_objfmt;
- else if (elf_march->bits == 32)
- objfmt_elf->objfmt.module = &yasm_elf32_LTX_objfmt;
- else if (elf_march->bits == 64)
- objfmt_elf->objfmt.module = &yasm_elf64_LTX_objfmt;
- }
- return objfmt;
- }
- static yasm_objfmt *
- elf32_objfmt_create(yasm_object *object)
- {
- return elf_objfmt_create_common(object, &yasm_elf32_LTX_objfmt, 32, NULL);
- }
- static yasm_objfmt *
- elf64_objfmt_create(yasm_object *object)
- {
- return elf_objfmt_create_common(object, &yasm_elf64_LTX_objfmt, 64, NULL);
- }
- static yasm_objfmt *
- elfx32_objfmt_create(yasm_object *object)
- {
- return elf_objfmt_create_common(object, &yasm_elfx32_LTX_objfmt, 32, NULL);
- }
- static long
- elf_objfmt_output_align(FILE *f, unsigned int align)
- {
- long pos;
- unsigned long delta;
- if (!is_exp2(align))
- yasm_internal_error("requested alignment not a power of two");
- pos = ftell(f);
- if (pos == -1) {
- yasm_error_set(YASM_ERROR_IO,
- N_("could not get file position on output file"));
- return -1;
- }
- delta = align - (pos & (align-1));
- if (delta != align) {
- pos += delta;
- if (fseek(f, pos, SEEK_SET) < 0) {
- yasm_error_set(YASM_ERROR_IO,
- N_("could not set file position on output file"));
- return -1;
- }
- }
- return pos;
- }
- static int
- elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc,
- unsigned char *buf, unsigned int destsize,
- unsigned int valsize, int warn, void *d)
- {
- elf_reloc_entry *reloc;
- elf_objfmt_output_info *info = d;
- yasm_intnum *zero;
- int retval;
- reloc = elf_reloc_entry_create(sym, NULL,
- yasm_intnum_create_uint(bc->offset), 0, valsize, 0);
- if (reloc == NULL) {
- yasm_error_set(YASM_ERROR_TYPE, N_("elf: invalid relocation size"));
- return 1;
- }
- /* allocate .rel[a] sections on a need-basis */
- elf_secthead_append_reloc(info->sect, info->shead, reloc);
- zero = yasm_intnum_create_uint(0);
- elf_handle_reloc_addend(zero, reloc, 0);
- retval = yasm_arch_intnum_tobytes(info->object->arch, zero, buf, destsize,
- valsize, 0, bc, warn);
- yasm_intnum_destroy(zero);
- return retval;
- }
- static int
- elf_objfmt_output_value(yasm_value *value, unsigned char *buf,
- unsigned int destsize, unsigned long offset,
- yasm_bytecode *bc, int warn, /*@null@*/ void *d)
- {
- /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- unsigned long intn_val;
- /*@null@*/ elf_reloc_entry *reloc = NULL;
- int retval;
- unsigned int valsize = value->size;
- if (info == NULL)
- yasm_internal_error("null info struct");
- if (value->abs)
- value->abs = yasm_expr_simplify(value->abs, 1);
- /* Try to output constant and PC-relative section-local first.
- * Note this does NOT output any value with a SEG, WRT, external,
- * cross-section, or non-PC-relative reference (those are handled below).
- */
- switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
- info->object->arch)) {
- case -1:
- return 1;
- case 0:
- break;
- default:
- return 0;
- }
- /* Handle other expressions, with relocation if necessary */
- if (value->seg_of || value->section_rel || value->rshift > 0) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("elf: relocation too complex"));
- return 1;
- }
- intn_val = 0;
- if (value->rel) {
- yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
- /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
- /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = value->wrt;
- if (wrt == info->objfmt_elf->dotdotsym)
- wrt = NULL;
- else if (wrt && elf_is_wrt_sym_relative(wrt))
- ;
- else if (wrt && elf_is_wrt_pos_adjusted(wrt))
- intn_val = offset + bc->offset;
- else if (vis == YASM_SYM_LOCAL) {
- yasm_bytecode *sym_precbc;
- /* Local symbols need relocation to their section's start, and
- * add in the offset of the bytecode (within the target section)
- * into the abs portion.
- *
- * This is only done if the symbol is relocated against the
- * section instead of the symbol itself.
- */
- if (yasm_symrec_get_label(sym, &sym_precbc)) {
- /* Relocate to section start */
- yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
- /*@null@*/ elf_secthead *sym_shead;
- sym_shead = yasm_section_get_data(sym_sect, &elf_section_data);
- assert(sym_shead != NULL);
- sym = elf_secthead_get_sym(sym_shead);
- intn_val = yasm_bc_next_offset(sym_precbc);
- }
- }
-
- /* For PC-relative, need to add offset of expression within bc. */
- if (value->curpos_rel)
- intn_val += offset;
- /* Check for _GLOBAL_OFFSET_TABLE_ symbol reference */
- reloc = elf_reloc_entry_create(sym, wrt,
- yasm_intnum_create_uint(bc->offset + offset), value->curpos_rel,
- valsize, sym == info->GOT_sym);
- if (reloc == NULL) {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("elf: invalid relocation (WRT or size)"));
- return 1;
- }
- /* allocate .rel[a] sections on a need-basis */
- elf_secthead_append_reloc(info->sect, info->shead, reloc);
- }
- intn = yasm_intnum_create_uint(intn_val);
- if (value->abs) {
- yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
- if (!intn2) {
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("elf: relocation too complex"));
- yasm_intnum_destroy(intn);
- return 1;
- }
- yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
- }
- if (reloc)
- elf_handle_reloc_addend(intn, reloc, offset);
- retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
- valsize, 0, bc, warn);
- yasm_intnum_destroy(intn);
- return retval;
- }
- static int
- elf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
- {
- /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
- unsigned char buf[256];
- /*@null@*/ /*@only@*/ unsigned char *bigbuf;
- unsigned long size = 256;
- int gap;
- if (info == NULL)
- yasm_internal_error("null info struct");
- bigbuf = yasm_bc_tobytes(bc, buf, &size, &gap, info,
- elf_objfmt_output_value, elf_objfmt_output_reloc);
- /* Don't bother doing anything else if size ended up being 0. */
- if (size == 0) {
- if (bigbuf)
- yasm_xfree(bigbuf);
- return 0;
- }
- else {
- yasm_intnum *bcsize = yasm_intnum_create_uint(size);
- elf_secthead_add_size(info->shead, bcsize);
- yasm_intnum_destroy(bcsize);
- }
- /* Warn that gaps are converted to 0 and write out the 0's. */
- if (gap) {
- unsigned long left;
- yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
- N_("uninitialized space declared in code/data section: zeroing"));
- /* Write out in chunks */
- memset(buf, 0, 256);
- left = size;
- while (left > 256) {
- fwrite(buf, 256, 1, info->f);
- left -= 256;
- }
- fwrite(buf, left, 1, info->f);
- } else {
- /* Output buf (or bigbuf if non-NULL) to file */
- fwrite(bigbuf ? bigbuf : buf, (size_t)size, 1, info->f);
- }
- /* If bigbuf was allocated, free it */
- if (bigbuf)
- yasm_xfree(bigbuf);
- return 0;
- }
- static int
- elf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
- {
- /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ elf_secthead *shead;
- long pos;
- char *relname;
- const char *sectname;
- if (info == NULL)
- yasm_internal_error("null info struct");
- shead = yasm_section_get_data(sect, &elf_section_data);
- if (shead == NULL)
- yasm_internal_error("no associated data");
- if (elf_secthead_get_align(shead) == 0)
- elf_secthead_set_align(shead, yasm_section_get_align(sect));
- /* don't output header-only sections */
- if ((elf_secthead_get_type(shead) & SHT_NOBITS) == SHT_NOBITS)
- {
- yasm_bytecode *last = yasm_section_bcs_last(sect);
- if (last) {
- yasm_intnum *sectsize;
- sectsize = yasm_intnum_create_uint(yasm_bc_next_offset(last));
- elf_secthead_add_size(shead, sectsize);
- yasm_intnum_destroy(sectsize);
- }
- elf_secthead_set_index(shead, ++info->sindex);
- return 0;
- }
- if ((pos = ftell(info->f)) == -1) {
- yasm_error_set(YASM_ERROR_IO,
- N_("couldn't read position on output stream"));
- yasm_errwarn_propagate(info->errwarns, 0);
- }
- pos = elf_secthead_set_file_offset(shead, pos);
- if (fseek(info->f, pos, SEEK_SET) < 0) {
- yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream"));
- yasm_errwarn_propagate(info->errwarns, 0);
- }
- info->sect = sect;
- info->shead = shead;
- yasm_section_bcs_traverse(sect, info->errwarns, info,
- elf_objfmt_output_bytecode);
- elf_secthead_set_index(shead, ++info->sindex);
- /* No relocations to output? Go on to next section */
- if (elf_secthead_write_relocs_to_file(info->f, sect, shead,
- info->errwarns) == 0)
- return 0;
- elf_secthead_set_rel_index(shead, ++info->sindex);
- /* name the relocation section .rel[a].foo */
- sectname = yasm_section_get_name(sect);
- relname = elf_secthead_name_reloc_section(sectname);
- elf_secthead_set_rel_name(shead,
- elf_strtab_append_str(info->objfmt_elf->shstrtab, relname));
- yasm_xfree(relname);
- return 0;
- }
- static int
- elf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
- {
- /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ elf_secthead *shead;
- if (info == NULL)
- yasm_internal_error("null info struct");
- shead = yasm_section_get_data(sect, &elf_section_data);
- if (shead == NULL)
- yasm_internal_error("no section header attached to section");
- if(elf_secthead_write_to_file(info->f, shead, info->sindex+1))
- info->sindex++;
- /* output strtab headers here? */
- /* relocation entries for .foo are stored in section .rel[a].foo */
- if(elf_secthead_write_rel_to_file(info->f, 3, sect, shead,
- info->sindex+1))
- info->sindex++;
- return 0;
- }
- static void
- elf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
- yasm_errwarns *errwarns)
- {
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- elf_objfmt_output_info info;
- build_symtab_info buildsym_info;
- long pos;
- unsigned long elf_shead_addr;
- elf_secthead *esdn;
- unsigned long elf_strtab_offset, elf_shstrtab_offset, elf_symtab_offset;
- unsigned long elf_strtab_size, elf_shstrtab_size, elf_symtab_size;
- elf_strtab_entry *elf_strtab_name, *elf_shstrtab_name, *elf_symtab_name;
- unsigned long elf_symtab_nlocal;
- info.object = object;
- info.objfmt_elf = objfmt_elf;
- info.errwarns = errwarns;
- info.f = f;
- info.GOT_sym = yasm_symtab_get(object->symtab, "_GLOBAL_OFFSET_TABLE_");
- if (!object->deb_filename) {
- object->deb_filename = yasm_replace_path(
- objfmt_elf->objfmt.module->replace_map, objfmt_elf->objfmt.module->replace_map_size,
- object->src_filename, strlen(object->src_filename));
- }
- /* Update filename strtab */
- elf_strtab_entry_set_str(objfmt_elf->file_strtab_entry,
- object->deb_filename);
- /* Allocate space for Ehdr by seeking forward */
- if (fseek(f, (long)(elf_proghead_get_size()), SEEK_SET) < 0) {
- yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file"));
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
- /* add all (local) syms to symtab because relocation needs a symtab index
- * if all_syms, register them by name. if not, use strtab entry 0 */
- buildsym_info.object = object;
- buildsym_info.objfmt_elf = objfmt_elf;
- buildsym_info.errwarns = errwarns;
- buildsym_info.local_names = all_syms;
- yasm_symtab_traverse(object->symtab, &buildsym_info,
- elf_objfmt_build_symtab);
- elf_symtab_nlocal = elf_symtab_assign_indices(objfmt_elf->elf_symtab);
- /* output known sections - includes reloc sections which aren't in yasm's
- * list. Assign indices as we go. */
- info.sindex = 3;
- if (yasm_object_sections_traverse(object, &info,
- elf_objfmt_output_section))
- return;
- /* add final sections to the shstrtab */
- elf_strtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".strtab");
- elf_symtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".symtab");
- elf_shstrtab_name = elf_strtab_append_str(objfmt_elf->shstrtab,
- ".shstrtab");
- /* output .shstrtab */
- if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
- elf_shstrtab_offset = (unsigned long) pos;
- elf_shstrtab_size = elf_strtab_output_to_file(f, objfmt_elf->shstrtab);
- /* output .strtab */
- if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
- elf_strtab_offset = (unsigned long) pos;
- elf_strtab_size = elf_strtab_output_to_file(f, objfmt_elf->strtab);
- /* output .symtab - last section so all others have indexes */
- if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
- elf_symtab_offset = (unsigned long) pos;
- elf_symtab_size = elf_symtab_write_to_file(f, objfmt_elf->elf_symtab,
- errwarns);
- /* output section header table */
- if ((pos = elf_objfmt_output_align(f, 16)) == -1) {
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
- elf_shead_addr = (unsigned long) pos;
- /* stabs debugging support */
- if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "stabs")==0) {
- yasm_section *stabsect = yasm_object_find_general(object, ".stab");
- yasm_section *stabstrsect =
- yasm_object_find_general(object, ".stabstr");
- if (stabsect && stabstrsect) {
- elf_secthead *stab =
- yasm_section_get_data(stabsect, &elf_section_data);
- elf_secthead *stabstr =
- yasm_section_get_data(stabstrsect, &elf_section_data);
- if (stab && stabstr) {
- elf_secthead_set_link(stab, elf_secthead_get_index(stabstr));
- }
- else
- yasm_internal_error(N_("missing .stab or .stabstr section/data"));
- }
- }
-
- /* output dummy section header - 0 */
- info.sindex = 0;
- esdn = elf_secthead_create(NULL, SHT_NULL, 0, 0, 0);
- elf_secthead_set_index(esdn, 0);
- elf_secthead_write_to_file(f, esdn, 0);
- elf_secthead_destroy(esdn);
- esdn = elf_secthead_create(elf_shstrtab_name, SHT_STRTAB, 0,
- elf_shstrtab_offset, elf_shstrtab_size);
- elf_secthead_set_index(esdn, 1);
- elf_secthead_write_to_file(f, esdn, 1);
- elf_secthead_destroy(esdn);
- esdn = elf_secthead_create(elf_strtab_name, SHT_STRTAB, 0,
- elf_strtab_offset, elf_strtab_size);
- elf_secthead_set_index(esdn, 2);
- elf_secthead_write_to_file(f, esdn, 2);
- elf_secthead_destroy(esdn);
- esdn = elf_secthead_create(elf_symtab_name, SHT_SYMTAB, 0,
- elf_symtab_offset, elf_symtab_size);
- elf_secthead_set_index(esdn, 3);
- elf_secthead_set_info(esdn, elf_symtab_nlocal);
- elf_secthead_set_link(esdn, 2); /* for .strtab, which is index 2 */
- elf_secthead_write_to_file(f, esdn, 3);
- elf_secthead_destroy(esdn);
- info.sindex = 3;
- /* output remaining section headers */
- yasm_object_sections_traverse(object, &info, elf_objfmt_output_secthead);
- /* output Ehdr */
- if (fseek(f, 0, SEEK_SET) < 0) {
- yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file"));
- yasm_errwarn_propagate(errwarns, 0);
- return;
- }
- elf_proghead_write_to_file(f, elf_shead_addr, info.sindex+1, 1);
- }
- static void
- elf_objfmt_destroy(yasm_objfmt *objfmt)
- {
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)objfmt;
- elf_symtab_destroy(objfmt_elf->elf_symtab);
- elf_strtab_destroy(objfmt_elf->shstrtab);
- elf_strtab_destroy(objfmt_elf->strtab);
- yasm_xfree(objfmt);
- }
- static void
- elf_objfmt_init_new_section(yasm_section *sect, unsigned long line)
- {
- yasm_object *object = yasm_section_get_object(sect);
- const char *sectname = yasm_section_get_name(sect);
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- elf_secthead *esd;
- yasm_symrec *sym;
- elf_strtab_entry *name = elf_strtab_append_str(objfmt_elf->shstrtab,
- sectname);
- elf_section_type type=SHT_PROGBITS;
- elf_size entsize=0;
- if (yasm__strcasecmp(sectname, ".stab")==0) {
- entsize = 12;
- } else if (yasm__strcasecmp(sectname, ".stabstr")==0) {
- type = SHT_STRTAB;
- }
- esd = elf_secthead_create(name, type, 0, 0, 0);
- elf_secthead_set_entsize(esd, entsize);
- yasm_section_add_data(sect, &elf_section_data, esd);
- sym = yasm_symtab_define_label(object->symtab, sectname,
- yasm_section_bcs_first(sect), 1, line);
- elf_secthead_set_sym(esd, sym);
- }
- static yasm_section *
- elf_objfmt_add_default_section(yasm_object *object)
- {
- yasm_section *retval;
- int isnew;
- retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0);
- if (isnew)
- {
- elf_secthead *esd = yasm_section_get_data(retval, &elf_section_data);
- elf_secthead_set_typeflags(esd, SHT_PROGBITS,
- SHF_ALLOC + SHF_EXECINSTR);
- yasm_section_set_default(retval, 1);
- }
- return retval;
- }
- struct elf_section_switch_data {
- /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
- unsigned long flags;
- unsigned long type;
- int gasflags;
- int stdsect;
- };
- /* GAS-style flags */
- static int
- elf_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
- /*@unused@*/ uintptr_t arg)
- {
- struct elf_section_switch_data *data = (struct elf_section_switch_data *)d;
- const char *s = yasm_vp_string(vp);
- size_t i;
- if (!s) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("non-string section attribute"));
- return -1;
- }
- if (data->stdsect && strlen(s) == 0) {
- data->gasflags = 1;
- return 0;
- }
- data->flags = 0;
- for (i=0; i<strlen(s); i++) {
- switch (s[i]) {
- case 'a':
- data->flags |= SHF_ALLOC;
- break;
- case 'w':
- data->flags |= SHF_WRITE;
- break;
- case 'x':
- data->flags |= SHF_EXECINSTR;
- break;
- case 'M':
- data->flags |= SHF_MERGE;
- break;
- case 'S':
- data->flags |= SHF_STRINGS;
- break;
- case 'G':
- data->flags |= SHF_GROUP;
- break;
- case 'T':
- data->flags |= SHF_TLS;
- break;
- default:
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("unrecognized section attribute: `%c'"),
- s[i]);
- }
- }
- data->gasflags = 1;
- return 0;
- }
- static /*@observer@*/ /*@null@*/ yasm_section *
- elf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
- /*@null@*/ yasm_valparamhead *objext_valparams,
- unsigned long line)
- {
- yasm_valparam *vp;
- yasm_section *retval;
- int isnew;
- unsigned long align = 4;
- int flags_override = 0;
- const char *sectname;
- int resonly = 0;
- struct elf_section_switch_data data;
- static const yasm_dir_help help[] = {
- { "alloc", 0, yasm_dir_helper_flag_or,
- offsetof(struct elf_section_switch_data, flags), SHF_ALLOC },
- { "exec", 0, yasm_dir_helper_flag_or,
- offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR },
- { "write", 0, yasm_dir_helper_flag_or,
- offsetof(struct elf_section_switch_data, flags), SHF_WRITE },
- { "tls", 0, yasm_dir_helper_flag_or,
- offsetof(struct elf_section_switch_data, flags), SHF_TLS },
- { "progbits", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_section_switch_data, type), SHT_PROGBITS },
- { "noalloc", 0, yasm_dir_helper_flag_and,
- offsetof(struct elf_section_switch_data, flags), SHF_ALLOC },
- { "noexec", 0, yasm_dir_helper_flag_and,
- offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR },
- { "nowrite", 0, yasm_dir_helper_flag_and,
- offsetof(struct elf_section_switch_data, flags), SHF_WRITE },
- { "notls", 0, yasm_dir_helper_flag_and,
- offsetof(struct elf_section_switch_data, flags), SHF_TLS },
- { "noprogbits", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_section_switch_data, type), SHT_NOBITS },
- { "nobits", 0, yasm_dir_helper_flag_set,
- offsetof(struct elf_section_switch_data, type), SHT_NOBITS },
- { "gasflags", 1, elf_helper_gasflags, 0, 0 },
- { "align", 1, yasm_dir_helper_intn,
- offsetof(struct elf_section_switch_data, align_intn), 0 }
- };
- /*@only@*/ /*@null@*/ yasm_expr *merge_expr = NULL;
- /*@dependent@*/ /*@null@*/ const yasm_intnum *merge_intn = NULL;
- elf_secthead *esd;
- data.align_intn = NULL;
- data.flags = SHF_ALLOC;
- data.type = SHT_PROGBITS;
- data.gasflags = 0;
- data.stdsect = 1;
- vp = yasm_vps_first(valparams);
- sectname = yasm_vp_string(vp);
- if (!sectname)
- return NULL;
- vp = yasm_vps_next(vp);
- if (strcmp(sectname, ".bss") == 0) {
- data.type = SHT_NOBITS;
- data.flags = SHF_ALLOC + SHF_WRITE;
- resonly = 1;
- } else if (strcmp(sectname, ".data") == 0) {
- data.type = SHT_PROGBITS;
- data.flags = SHF_ALLOC + SHF_WRITE;
- } else if (strcmp(sectname, ".tdata") == 0) {
- data.type = SHT_PROGBITS;
- data.flags = SHF_ALLOC + SHF_WRITE + SHF_TLS;
- } else if (strcmp(sectname, ".rodata") == 0) {
- data.type = SHT_PROGBITS;
- data.flags = SHF_ALLOC;
- } else if (strcmp(sectname, ".text") == 0) {
- align = 16;
- data.type = SHT_PROGBITS;
- data.flags = SHF_ALLOC + SHF_EXECINSTR;
- } else if (strcmp(sectname, ".comment") == 0) {
- align = 0;
- data.type = SHT_PROGBITS;
- data.flags = 0;
- } else {
- /* Default to code */
- align = 1;
- data.stdsect = 0;
- }
- flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
- &data, yasm_dir_helper_valparam_warn);
- if (flags_override < 0)
- return NULL; /* error occurred */
- if (data.align_intn) {
- align = yasm_intnum_get_uint(data.align_intn);
- yasm_intnum_destroy(data.align_intn);
- /* Alignments must be a power of two. */
- if (!is_exp2(align)) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("argument to `%s' is not a power of two"),
- "align");
- return NULL;
- }
- }
- /* Handle merge entity size */
- if (data.flags & SHF_MERGE) {
- if (objext_valparams && (vp = yasm_vps_first(objext_valparams))
- && !vp->val) {
- if (!(merge_expr = yasm_vp_expr(vp, object->symtab, line)) ||
- !(merge_intn = yasm_expr_get_intnum(&merge_expr, 0)))
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("invalid merge entity size"));
- } else {
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("entity size for SHF_MERGE not specified"));
- data.flags &= ~SHF_MERGE;
- }
- }
- retval = yasm_object_get_general(object, sectname, align,
- (data.flags & SHF_EXECINSTR) != 0,
- resonly, &isnew, line);
- esd = yasm_section_get_data(retval, &elf_section_data);
- if (isnew || yasm_section_is_default(retval)) {
- yasm_section_set_default(retval, 0);
- elf_secthead_set_typeflags(esd, data.type, data.flags);
- if (merge_intn)
- elf_secthead_set_entsize(esd, yasm_intnum_get_uint(merge_intn));
- yasm_section_set_align(retval, align, line);
- } else if (flags_override && !data.gasflags)
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("section flags ignored on section redeclaration"));
- if (merge_expr)
- yasm_expr_destroy(merge_expr);
- return retval;
- }
- static /*@observer@*/ /*@null@*/ yasm_symrec *
- elf_objfmt_get_special_sym(yasm_object *object, const char *name,
- const char *parser)
- {
- if (yasm__strcasecmp(name, "sym") == 0) {
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- return objfmt_elf->dotdotsym;
- }
- return elf_get_special_sym(name, parser);
- }
- static void
- dir_type(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
- {
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- const char *symname = yasm_vp_id(vp);
- /* Get symbol elf data */
- yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line);
- elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
- /*@null@*/ const char *type;
- /* Create entry if necessary */
- if (!entry) {
- entry = elf_symtab_entry_create(
- elf_strtab_append_str(objfmt_elf->strtab, symname), sym);
- yasm_symrec_add_data(sym, &elf_symrec_data, entry);
- }
- /* Pull new type from param */
- vp = yasm_vps_next(vp);
- if (vp && !vp->val && (type = yasm_vp_id(vp))) {
- if (yasm__strcasecmp(type, "function") == 0)
- elf_sym_set_type(entry, STT_FUNC);
- else if (yasm__strcasecmp(type, "object") == 0)
- elf_sym_set_type(entry, STT_OBJECT);
- else if (yasm__strcasecmp(type, "tls_object") == 0)
- elf_sym_set_type(entry, STT_TLS);
- else if (yasm__strcasecmp(type, "notype") == 0)
- elf_sym_set_type(entry, STT_NOTYPE);
- else
- yasm_warn_set(YASM_WARN_GENERAL,
- N_("unrecognized symbol type `%s'"), type);
- } else
- yasm_error_set(YASM_ERROR_SYNTAX, N_("no type specified"));
- }
- static void
- dir_size(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
- {
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- const char *symname = yasm_vp_id(vp);
- /* Get symbol elf data */
- yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line);
- elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
- /*@only@*/ /*@null@*/ yasm_expr *size;
- /* Create entry if necessary */
- if (!entry) {
- entry = elf_symtab_entry_create(
- elf_strtab_append_str(objfmt_elf->strtab, symname), sym);
- yasm_symrec_add_data(sym, &elf_symrec_data, entry);
- }
- /* Pull new size from param */
- vp = yasm_vps_next(vp);
- if (vp && !vp->val && (size = yasm_vp_expr(vp, object->symtab, line)))
- elf_sym_set_size(entry, size);
- else
- yasm_error_set(YASM_ERROR_SYNTAX, N_("no size specified"));
- }
- static void
- dir_weak(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
- {
- yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
- yasm_valparam *vp = yasm_vps_first(valparams);
- const char *symname = yasm_vp_id(vp);
- yasm_symrec *sym = yasm_symtab_declare(object->symtab, symname,
- YASM_SYM_GLOBAL, line);
- elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_WEAK, 0,
- STV_DEFAULT, NULL, NULL, object);
- }
- static void
- dir_ident(yasm_object *object, yasm_valparamhead *valparams,
- yasm_valparamhead *objext_valparams, unsigned long line)
- {
- yasm_valparamhead sect_vps;
- yasm_datavalhead dvs;
- yasm_section *comment;
- yasm_valparam *vp;
- yasm_valparam *vp2;
- /* Accept, but do nothing with empty ident */
- if (!valparams)
- return;
- vp = yasm_vps_first(valparams);
- if (!vp)
- return;
- /* Put ident data into .comment section */
- yasm_vps_initialize(§_vps);
- vp2 = yasm_vp_create_string(NULL, yasm__xstrdup(".comment"));
- yasm_vps_append(§_vps, vp2);
- comment = elf_objfmt_section_switch(object, §_vps, NULL, line);
- yasm_vps_delete(§_vps);
- /* To match GAS output, if the comment section is empty, put an
- * initial 0 byte in the section.
- */
- if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
- yasm_dvs_initialize(&dvs);
- yasm_dvs_append(&dvs, yasm_dv_create_expr(
- yasm_expr_create_ident(
- yasm_expr_int(yasm_intnum_create_uint(0)), line)));
- yasm_section_bcs_append(comment,
- yasm_bc_create_data(&dvs, 1, 0, object->arch, line));
- }
- yasm_dvs_initialize(&dvs);
- do {
- const char *s = yasm_vp_string(vp);
- if (!s) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_(".comment requires string parameters"));
- yasm_dvs_delete(&dvs);
- return;
- }
- yasm_dvs_append(&dvs,
- yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
- } while ((vp = yasm_vps_next(vp)));
- yasm_section_bcs_append(comment,
- yasm_bc_create_data(&dvs, 1, 1, object->arch, line));
- }
- /* Define valid debug formats to use with this object format */
- static const char *elf_objfmt_dbgfmt_keywords[] = {
- "null",
- "stabs",
- "dwarf2",
- NULL
- };
- static const yasm_directive elf_objfmt_directives[] = {
- { ".type", "gas", dir_type, YASM_DIR_ID_REQUIRED },
- { ".size", "gas", dir_size, YASM_DIR_ID_REQUIRED },
- { ".weak", "gas", dir_weak, YASM_DIR_ID_REQUIRED },
- { ".ident", "gas", dir_ident, YASM_DIR_ANY },
- { "type", "nasm", dir_type, YASM_DIR_ID_REQUIRED },
- { "size", "nasm", dir_size, YASM_DIR_ID_REQUIRED },
- { "weak", "nasm", dir_weak, YASM_DIR_ID_REQUIRED },
- { "ident", "nasm", dir_ident, YASM_DIR_ANY },
- { NULL, NULL, NULL, 0 }
- };
- static const char *elf_nasm_stdmac[] = {
- "%imacro type 1+.nolist",
- "[type %1]",
- "%endmacro",
- "%imacro size 1+.nolist",
- "[size %1]",
- "%endmacro",
- "%imacro weak 1+.nolist",
- "[weak %1]",
- "%endmacro",
- NULL
- };
- static const yasm_stdmac elf_objfmt_stdmacs[] = {
- { "nasm", "nasm", elf_nasm_stdmac },
- { NULL, NULL, NULL }
- };
- /* Define objfmt structure -- see objfmt.h for details */
- yasm_objfmt_module yasm_elf_LTX_objfmt = {
- "ELF",
- "elf",
- "o",
- 32,
- 0,
- elf_objfmt_dbgfmt_keywords,
- "null",
- elf_objfmt_directives,
- elf_objfmt_stdmacs,
- elf_objfmt_create,
- elf_objfmt_output,
- elf_objfmt_destroy,
- elf_objfmt_add_default_section,
- elf_objfmt_init_new_section,
- elf_objfmt_section_switch,
- elf_objfmt_get_special_sym
- };
- yasm_objfmt_module yasm_elf32_LTX_objfmt = {
- "ELF (32-bit)",
- "elf32",
- "o",
- 32,
- 0,
- elf_objfmt_dbgfmt_keywords,
- "null",
- elf_objfmt_directives,
- elf_objfmt_stdmacs,
- elf32_objfmt_create,
- elf_objfmt_output,
- elf_objfmt_destroy,
- elf_objfmt_add_default_section,
- elf_objfmt_init_new_section,
- elf_objfmt_section_switch,
- elf_objfmt_get_special_sym
- };
- yasm_objfmt_module yasm_elf64_LTX_objfmt = {
- "ELF (64-bit)",
- "elf64",
- "o",
- 64,
- 0,
- elf_objfmt_dbgfmt_keywords,
- "null",
- elf_objfmt_directives,
- elf_objfmt_stdmacs,
- elf64_objfmt_create,
- elf_objfmt_output,
- elf_objfmt_destroy,
- elf_objfmt_add_default_section,
- elf_objfmt_init_new_section,
- elf_objfmt_section_switch,
- elf_objfmt_get_special_sym
- };
- yasm_objfmt_module yasm_elfx32_LTX_objfmt = {
- "ELF (x32)",
- "elfx32",
- "o",
- 64,
- 0,
- elf_objfmt_dbgfmt_keywords,
- "null",
- elf_objfmt_directives,
- elf_objfmt_stdmacs,
- elfx32_objfmt_create,
- elf_objfmt_output,
- elf_objfmt_destroy,
- elf_objfmt_add_default_section,
- elf_objfmt_init_new_section,
- elf_objfmt_section_switch,
- elf_objfmt_get_special_sym
- };
|