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. */
46 static 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 };
58 const struct FillPattern *__libasm_default_pattern = &xdefault_pattern.pattern;
59
60
61 static AsmScn_t *
text_newscn(AsmScn_t * result,GElf_Word type,GElf_Xword flags)62 text_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
104 static AsmScn_t *
binary_newscn(AsmScn_t * result,GElf_Word type,GElf_Xword flags,size_t scnname_len)105 binary_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
158 AsmScn_t *
asm_newscn(AsmCtx_t * ctx,const char * scnname,GElf_Word type,GElf_Xword flags)159 asm_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 }
210 INTDEF(asm_newscn)
211