1/* Create new section in output file.
2   Copyright (C) 2002 Red Hat, Inc.
3   Written by Ulrich Drepper <drepper@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.  */
33static 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  };
45const struct FillPattern *__libasm_default_pattern = &xdefault_pattern.pattern;
46
47
48static AsmScn_t *
49text_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
90static AsmScn_t *
91binary_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
144AsmScn_t *
145asm_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}
202INTDEF(asm_newscn)
203