Home | History | Annotate | Download | only in libasm
      1 /* Create new section in output file.
      2    Copyright (C) 2002 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) redhat.com>, 2002.
      4 
      5    This program is Open Source software; you can redistribute it and/or
      6    modify it under the terms of the Open Software License version 1.0 as
      7    published by the Open Source Initiative.
      8 
      9    You should have received a copy of the Open Software License along
     10    with this program; if not, you may obtain a copy of the Open Software
     11    License version 1.0 from http://www.opensource.org/licenses/osl.php or
     12    by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
     13    3001 King Ranch Road, Ukiah, CA 95482.   */
     14 
     15 #ifdef HAVE_CONFIG_H
     16 # include <config.h>
     17 #endif
     18 
     19 #include <assert.h>
     20 #include <error.h>
     21 #include <libintl.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 
     25 #include <libasmP.h>
     26 #include <libelf.h>
     27 #include <system.h>
     28 
     29 
     30 /* Memory for the default pattern.  The type uses a flexible array
     31    which does work well with a static initializer.  So we play some
     32    dirty tricks here.  */
     33 static const struct
     34 {
     35   struct FillPattern pattern;
     36   char zero;
     37 } xdefault_pattern =
     38   {
     39     .pattern =
     40     {
     41       .len = 1
     42     },
     43     .zero = '\0'
     44   };
     45 const struct FillPattern *__libasm_default_pattern = &xdefault_pattern.pattern;
     46 
     47 
     48 static AsmScn_t *
     49 text_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags)
     50 {
     51   /* Buffer where we construct the flag string.  */
     52   char flagstr[sizeof (GElf_Xword) * 8 + 5];
     53   char *wp = flagstr;
     54   const char *typestr = "";
     55 
     56   /* Only write out the flag string if this is the first time the
     57      section is selected.  Some assemblers cannot cope with the
     58      .section pseudo-op otherwise.  */
     59   wp = stpcpy (wp, ", \"");
     60 
     61   if (flags & SHF_WRITE)
     62     *wp++ = 'w';
     63   if (flags & SHF_ALLOC)
     64     *wp++ = 'a';
     65   if (flags & SHF_EXECINSTR)
     66     *wp++ = 'x';
     67   if (flags & SHF_MERGE)
     68     *wp++ = 'M';
     69   if (flags & SHF_STRINGS)
     70     *wp++ = 'S';
     71   if (flags & SHF_LINK_ORDER)
     72     *wp++ = 'L';
     73 
     74   *wp++ = '"';
     75 
     76   if (type == SHT_PROGBITS)
     77     typestr = ",@progbits";
     78   else if (type == SHT_NOBITS)
     79     typestr = ",@nobits";
     80 
     81   /* Terminate the string.  */
     82   *wp = '\0';
     83 
     84   printf ("\t.section \"%s\"%s%s\n", result->name, flagstr, typestr);
     85 
     86   return result;
     87 }
     88 
     89 
     90 static AsmScn_t *
     91 binary_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags,
     92 	       size_t scnname_len)
     93 {
     94   GElf_Shdr shdr_mem;
     95   GElf_Shdr *shdr;
     96   Elf_Scn *scn;
     97 
     98   /* The initial subsection has the number zero.  */
     99   result->subsection_id = 0;
    100 
    101   /* We start at offset zero.  */
    102   result->offset = 0;
    103   /* And generic alignment.  */
    104   result->max_align = 1;
    105 
    106   /* No output yet.  */
    107   result->content = NULL;
    108 
    109   /* Put the default fill pattern in place.  */
    110   result->pattern = (struct FillPattern *) __libasm_default_pattern;
    111 
    112   /* There are no subsections so far.  */
    113   result->subnext = NULL;
    114 
    115   /* Add the name to the section header string table.  */
    116   result->data.main.strent = ebl_strtabadd (result->ctx->section_strtab,
    117 					    result->name, scnname_len);
    118   assert (result->data.main.strent != NULL);
    119 
    120   /* Create the new ELF section.  */
    121   result->data.main.scn = scn = elf_newscn (result->ctx->out.elf);
    122   if (scn == NULL)
    123     {
    124       free (result);
    125       __libasm_seterrno (ASM_E_LIBELF);
    126       return NULL;
    127     }
    128 
    129   /* Not part of a section group (yet).  */
    130   result->data.main.next_in_group = NULL;
    131 
    132   /* Remember the flags.  */
    133   shdr = gelf_getshdr (scn, &shdr_mem);
    134 
    135   shdr->sh_flags = flags;
    136   result->type = shdr->sh_type = type;
    137 
    138   (void) gelf_update_shdr (scn, shdr);
    139 
    140   return result;
    141 }
    142 
    143 
    144 AsmScn_t *
    145 asm_newscn (ctx, scnname, type, flags)
    146      AsmCtx_t *ctx;
    147      const char *scnname;
    148      GElf_Word type;
    149      GElf_Xword flags;
    150 {
    151   size_t scnname_len = strlen (scnname) + 1;
    152   unsigned long int hval;
    153   AsmScn_t *result;
    154 
    155   /* If no context is given there might be an earlier error.  */
    156   if (ctx == NULL)
    157     return NULL;
    158 
    159   /* Check whether only flags are set which areselectable by the user.  */
    160   if (unlikely ((flags & ~(SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE
    161 			   | SHF_STRINGS | SHF_LINK_ORDER)) != 0)
    162       /* We allow only two section types: data and data without file
    163 	 representation.  */
    164       || (type != SHT_PROGBITS && unlikely (type != SHT_NOBITS)))
    165     {
    166       __libasm_seterrno (ASM_E_INVALID);
    167       return NULL;
    168     }
    169 
    170   hval = elf_hash (scnname);
    171 
    172   rwlock_wrlock (ctx->lock);
    173 
    174   /* This is a new section.  */
    175   result = (AsmScn_t *) malloc (sizeof (AsmScn_t) + scnname_len);
    176   if (result != NULL)
    177     {
    178       /* Add the name.  */
    179       memcpy (result->name, scnname, scnname_len);
    180 
    181       /* Add the reference to the context.  */
    182       result->ctx = ctx;
    183 
    184       /* Perform operations according to output mode.  */
    185       result = (unlikely (ctx->textp)
    186 		? text_newscn (result, type, flags)
    187 		: binary_newscn (result, type, flags, scnname_len));
    188 
    189       /* If everything went well finally add the new section to the hash
    190 	 table.  */
    191       if (result != NULL)
    192 	{
    193 	  result->allnext = ctx->section_list;
    194 	  ctx->section_list = result;
    195 	}
    196     }
    197 
    198   rwlock_unlock (ctx->lock);
    199 
    200   return result;
    201 }
    202 INTDEF(asm_newscn)
    203