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