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