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