diff options
Diffstat (limited to 'libasm/asm_newscn.c')
-rw-r--r-- | libasm/asm_newscn.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/libasm/asm_newscn.c b/libasm/asm_newscn.c new file mode 100644 index 00000000..75890a60 --- /dev/null +++ b/libasm/asm_newscn.c @@ -0,0 +1,202 @@ +/* Create new section in output file. + Copyright (C) 2002 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <error.h> +#include <libintl.h> +#include <stdlib.h> +#include <string.h> + +#include <libasmP.h> +#include <libelf.h> +#include <system.h> + + +/* Memory for the default pattern. The type uses a flexible array + which does work well with a static initializer. So we play some + dirty tricks here. */ +static const struct +{ + struct FillPattern pattern; + char zero; +} xdefault_pattern = + { + .pattern = + { + .len = 1 + }, + .zero = '\0' + }; +const struct FillPattern *__libasm_default_pattern = &xdefault_pattern.pattern; + + +static AsmScn_t * +text_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags) +{ + /* Buffer where we construct the flag string. */ + char flagstr[sizeof (GElf_Xword) * 8 + 5]; + char *wp = flagstr; + const char *typestr = ""; + + /* Only write out the flag string if this is the first time the + section is selected. Some assemblers cannot cope with the + .section pseudo-op otherwise. */ + wp = stpcpy (wp, ", \""); + + if (flags & SHF_WRITE) + *wp++ = 'w'; + if (flags & SHF_ALLOC) + *wp++ = 'a'; + if (flags & SHF_EXECINSTR) + *wp++ = 'x'; + if (flags & SHF_MERGE) + *wp++ = 'M'; + if (flags & SHF_STRINGS) + *wp++ = 'S'; + if (flags & SHF_LINK_ORDER) + *wp++ = 'L'; + + *wp++ = '"'; + + if (type == SHT_PROGBITS) + typestr = ",@progbits"; + else if (type == SHT_NOBITS) + typestr = ",@nobits"; + + /* Terminate the string. */ + *wp = '\0'; + + printf ("\t.section \"%s\"%s%s\n", result->name, flagstr, typestr); + + return result; +} + + +static AsmScn_t * +binary_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags, + size_t scnname_len) +{ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Scn *scn; + + /* The initial subsection has the number zero. */ + result->subsection_id = 0; + + /* We start at offset zero. */ + result->offset = 0; + /* And generic alignment. */ + result->max_align = 1; + + /* No output yet. */ + result->content = NULL; + + /* Put the default fill pattern in place. */ + result->pattern = (struct FillPattern *) __libasm_default_pattern; + + /* There are no subsections so far. */ + result->subnext = NULL; + + /* Add the name to the section header string table. */ + result->data.main.strent = ebl_strtabadd (result->ctx->section_strtab, + result->name, scnname_len); + assert (result->data.main.strent != NULL); + + /* Create the new ELF section. */ + result->data.main.scn = scn = elf_newscn (result->ctx->out.elf); + if (scn == NULL) + { + free (result); + __libasm_seterrno (ASM_E_LIBELF); + return NULL; + } + + /* Not part of a section group (yet). */ + result->data.main.next_in_group = NULL; + + /* Remember the flags. */ + shdr = gelf_getshdr (scn, &shdr_mem); + + shdr->sh_flags = flags; + result->type = shdr->sh_type = type; + + (void) gelf_update_shdr (scn, shdr); + + return result; +} + + +AsmScn_t * +asm_newscn (ctx, scnname, type, flags) + AsmCtx_t *ctx; + const char *scnname; + GElf_Word type; + GElf_Xword flags; +{ + size_t scnname_len = strlen (scnname) + 1; + unsigned long int hval; + AsmScn_t *result; + + /* If no context is given there might be an earlier error. */ + if (ctx == NULL) + return NULL; + + /* Check whether only flags are set which areselectable by the user. */ + if (unlikely ((flags & ~(SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE + | SHF_STRINGS | SHF_LINK_ORDER)) != 0) + /* We allow only two section types: data and data without file + representation. */ + || (type != SHT_PROGBITS && unlikely (type != SHT_NOBITS))) + { + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + hval = elf_hash (scnname); + + rwlock_wrlock (ctx->lock); + + /* This is a new section. */ + result = (AsmScn_t *) malloc (sizeof (AsmScn_t) + scnname_len); + if (result != NULL) + { + /* Add the name. */ + memcpy (result->name, scnname, scnname_len); + + /* Add the reference to the context. */ + result->ctx = ctx; + + /* Perform operations according to output mode. */ + result = (unlikely (ctx->textp) + ? text_newscn (result, type, flags) + : binary_newscn (result, type, flags, scnname_len)); + + /* If everything went well finally add the new section to the hash + table. */ + if (result != NULL) + { + result->allnext = ctx->section_list; + ctx->section_list = result; + } + } + + rwlock_unlock (ctx->lock); + + return result; +} +INTDEF(asm_newscn) |