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