xref: /aosp_15_r20/external/elfutils/libasm/asm_newscn.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
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