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. */
33 static 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 };
45 const struct FillPattern *__libasm_default_pattern = &xdefault_pattern.pattern;
46
47
48 static AsmScn_t *
text_newscn(AsmScn_t * result,GElf_Word type,GElf_Xword flags)49 text_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
90 static AsmScn_t *
binary_newscn(AsmScn_t * result,GElf_Word type,GElf_Xword flags,size_t scnname_len)91 binary_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
144 AsmScn_t *
asm_newscn(ctx,scnname,type,flags)145 asm_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 }
202 INTDEF(asm_newscn)
203