1/* Create new section in output file.
2   Copyright (C) 2002-2011 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 <error.h>
36#include <libintl.h>
37#include <stdlib.h>
38#include <string.h>
39
40#include <libasmP.h>
41#include <libelf.h>
42#include <system.h>
43
44
45/* Memory for the default pattern.  The type uses a flexible array
46   which does work well with a static initializer.  So we play some
47   dirty tricks here.  */
48static const struct
49{
50  struct FillPattern pattern;
51  char zero;
52} xdefault_pattern =
53  {
54    .pattern =
55    {
56      .len = 1
57    },
58    .zero = '\0'
59  };
60const struct FillPattern *__libasm_default_pattern = &xdefault_pattern.pattern;
61
62
63static AsmScn_t *
64text_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags)
65{
66  /* Buffer where we construct the flag string.  */
67  char flagstr[sizeof (GElf_Xword) * 8 + 5];
68  char *wp = flagstr;
69  const char *typestr = "";
70
71  /* Only write out the flag string if this is the first time the
72     section is selected.  Some assemblers cannot cope with the
73     .section pseudo-op otherwise.  */
74  wp = stpcpy (wp, ", \"");
75
76  if (flags & SHF_WRITE)
77    *wp++ = 'w';
78  if (flags & SHF_ALLOC)
79    *wp++ = 'a';
80  if (flags & SHF_EXECINSTR)
81    *wp++ = 'x';
82  if (flags & SHF_MERGE)
83    *wp++ = 'M';
84  if (flags & SHF_STRINGS)
85    *wp++ = 'S';
86  if (flags & SHF_LINK_ORDER)
87    *wp++ = 'L';
88
89  *wp++ = '"';
90
91  if (type == SHT_PROGBITS)
92    typestr = ",@progbits";
93  else if (type == SHT_NOBITS)
94    typestr = ",@nobits";
95
96  /* Terminate the string.  */
97  *wp = '\0';
98
99  fprintf (result->ctx->out.file, "\t.section \"%s\"%s%s\n",
100	   result->name, flagstr, typestr);
101
102  return result;
103}
104
105
106static AsmScn_t *
107binary_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags,
108	       size_t scnname_len)
109{
110  GElf_Shdr shdr_mem;
111  GElf_Shdr *shdr;
112  Elf_Scn *scn;
113
114  /* The initial subsection has the number zero.  */
115  result->subsection_id = 0;
116
117  /* We start at offset zero.  */
118  result->offset = 0;
119  /* And generic alignment.  */
120  result->max_align = 1;
121
122  /* No output yet.  */
123  result->content = NULL;
124
125  /* Put the default fill pattern in place.  */
126  result->pattern = (struct FillPattern *) __libasm_default_pattern;
127
128  /* There are no subsections so far.  */
129  result->subnext = NULL;
130
131  /* Add the name to the section header string table.  */
132  result->data.main.strent = ebl_strtabadd (result->ctx->section_strtab,
133					    result->name, scnname_len);
134  assert (result->data.main.strent != NULL);
135
136  /* Create the new ELF section.  */
137  result->data.main.scn = scn = elf_newscn (result->ctx->out.elf);
138  if (scn == NULL)
139    {
140      free (result);
141      __libasm_seterrno (ASM_E_LIBELF);
142      return NULL;
143    }
144
145  /* Not part of a section group (yet).  */
146  result->data.main.next_in_group = NULL;
147
148  /* Remember the flags.  */
149  shdr = gelf_getshdr (scn, &shdr_mem);
150
151  shdr->sh_flags = flags;
152  result->type = shdr->sh_type = type;
153
154  (void) gelf_update_shdr (scn, shdr);
155
156  return result;
157}
158
159
160AsmScn_t *
161asm_newscn (AsmCtx_t *ctx, const char *scnname, GElf_Word type,
162	    GElf_Xword flags)
163{
164  size_t scnname_len = strlen (scnname) + 1;
165  AsmScn_t *result;
166
167  /* If no context is given there might be an earlier error.  */
168  if (ctx == NULL)
169    return NULL;
170
171  /* Check whether only flags are set which areselectable by the user.  */
172  if (unlikely ((flags & ~(SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE
173			   | SHF_STRINGS | SHF_LINK_ORDER)) != 0)
174      /* We allow only two section types: data and data without file
175	 representation.  */
176      || (type != SHT_PROGBITS && unlikely (type != SHT_NOBITS)))
177    {
178      __libasm_seterrno (ASM_E_INVALID);
179      return NULL;
180    }
181
182  rwlock_wrlock (ctx->lock);
183
184  /* This is a new section.  */
185  result = (AsmScn_t *) malloc (sizeof (AsmScn_t) + scnname_len);
186  if (result != NULL)
187    {
188      /* Add the name.  */
189      memcpy (result->name, scnname, scnname_len);
190
191      /* Add the reference to the context.  */
192      result->ctx = ctx;
193
194      /* Perform operations according to output mode.  */
195      result = (unlikely (ctx->textp)
196		? text_newscn (result, type, flags)
197		: binary_newscn (result, type, flags, scnname_len));
198
199      /* If everything went well finally add the new section to the hash
200	 table.  */
201      if (result != NULL)
202	{
203	  result->allnext = ctx->section_list;
204	  ctx->section_list = result;
205	}
206    }
207
208  rwlock_unlock (ctx->lock);
209
210  return result;
211}
212INTDEF(asm_newscn)
213