/* 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)