1 /* Create new section in output file. 2 Copyright (C) 2002 Red Hat, Inc. 3 Written by Ulrich Drepper <drepper (at) 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 * 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 * 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 * 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