1da0c48c4Sopenharmony_ci/* Finalize operations on the assembler context, free all resources. 2da0c48c4Sopenharmony_ci Copyright (C) 2002, 2003, 2005, 2016 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 2002. 5da0c48c4Sopenharmony_ci 6da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 7da0c48c4Sopenharmony_ci it under the terms of either 8da0c48c4Sopenharmony_ci 9da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 10da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 11da0c48c4Sopenharmony_ci your option) any later version 12da0c48c4Sopenharmony_ci 13da0c48c4Sopenharmony_ci or 14da0c48c4Sopenharmony_ci 15da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 16da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 17da0c48c4Sopenharmony_ci your option) any later version 18da0c48c4Sopenharmony_ci 19da0c48c4Sopenharmony_ci or both in parallel, as here. 20da0c48c4Sopenharmony_ci 21da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 22da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 23da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24da0c48c4Sopenharmony_ci General Public License for more details. 25da0c48c4Sopenharmony_ci 26da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 27da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 28da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 29da0c48c4Sopenharmony_ci 30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 31da0c48c4Sopenharmony_ci# include <config.h> 32da0c48c4Sopenharmony_ci#endif 33da0c48c4Sopenharmony_ci 34da0c48c4Sopenharmony_ci#include <assert.h> 35da0c48c4Sopenharmony_ci#include <stdio.h> 36da0c48c4Sopenharmony_ci#include <stdlib.h> 37da0c48c4Sopenharmony_ci#include <string.h> 38da0c48c4Sopenharmony_ci#include <sys/stat.h> 39da0c48c4Sopenharmony_ci 40da0c48c4Sopenharmony_ci#include <libasmP.h> 41da0c48c4Sopenharmony_ci#include <libelf.h> 42da0c48c4Sopenharmony_ci 43da0c48c4Sopenharmony_ci 44da0c48c4Sopenharmony_cistatic int 45da0c48c4Sopenharmony_citext_end (AsmCtx_t *ctx __attribute__ ((unused))) 46da0c48c4Sopenharmony_ci{ 47da0c48c4Sopenharmony_ci if (fflush (ctx->out.file) != 0) 48da0c48c4Sopenharmony_ci { 49da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_IOERROR); 50da0c48c4Sopenharmony_ci return -1; 51da0c48c4Sopenharmony_ci } 52da0c48c4Sopenharmony_ci 53da0c48c4Sopenharmony_ci return 0; 54da0c48c4Sopenharmony_ci} 55da0c48c4Sopenharmony_ci 56da0c48c4Sopenharmony_ci 57da0c48c4Sopenharmony_cistatic int 58da0c48c4Sopenharmony_cibinary_end (AsmCtx_t *ctx) 59da0c48c4Sopenharmony_ci{ 60da0c48c4Sopenharmony_ci void *symtab = NULL; 61da0c48c4Sopenharmony_ci Dwelf_Strent *symscn_strent = NULL; 62da0c48c4Sopenharmony_ci Dwelf_Strent *strscn_strent = NULL; 63da0c48c4Sopenharmony_ci Dwelf_Strent *xndxscn_strent = NULL; 64da0c48c4Sopenharmony_ci Elf_Scn *shstrscn; 65da0c48c4Sopenharmony_ci Dwelf_Strent *shstrscn_strent; 66da0c48c4Sopenharmony_ci size_t shstrscnndx; 67da0c48c4Sopenharmony_ci size_t symscnndx = 0; 68da0c48c4Sopenharmony_ci size_t strscnndx = 0; 69da0c48c4Sopenharmony_ci size_t xndxscnndx = 0; 70da0c48c4Sopenharmony_ci Elf_Data *data; 71da0c48c4Sopenharmony_ci Elf_Data *shstrtabdata; 72da0c48c4Sopenharmony_ci Elf_Data *strtabdata = NULL; 73da0c48c4Sopenharmony_ci Elf_Data *xndxdata = NULL; 74da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 75da0c48c4Sopenharmony_ci GElf_Shdr *shdr; 76da0c48c4Sopenharmony_ci GElf_Ehdr ehdr_mem; 77da0c48c4Sopenharmony_ci GElf_Ehdr *ehdr; 78da0c48c4Sopenharmony_ci AsmScn_t *asmscn; 79da0c48c4Sopenharmony_ci int result = 0; 80da0c48c4Sopenharmony_ci 81da0c48c4Sopenharmony_ci /* Iterate over the created sections and compute the offsets of the 82da0c48c4Sopenharmony_ci various subsections and fill in the content. */ 83da0c48c4Sopenharmony_ci for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext) 84da0c48c4Sopenharmony_ci { 85da0c48c4Sopenharmony_ci#if 0 86da0c48c4Sopenharmony_ci Elf_Scn *scn = elf_getscn (ctx->out.elf, asmscn->data.main.scnndx); 87da0c48c4Sopenharmony_ci#else 88da0c48c4Sopenharmony_ci Elf_Scn *scn = asmscn->data.main.scn; 89da0c48c4Sopenharmony_ci#endif 90da0c48c4Sopenharmony_ci off_t offset = 0; 91da0c48c4Sopenharmony_ci AsmScn_t *asmsubscn = asmscn; 92da0c48c4Sopenharmony_ci 93da0c48c4Sopenharmony_ci do 94da0c48c4Sopenharmony_ci { 95da0c48c4Sopenharmony_ci struct AsmData *content = asmsubscn->content; 96da0c48c4Sopenharmony_ci bool first = true; 97da0c48c4Sopenharmony_ci 98da0c48c4Sopenharmony_ci offset = ((offset + asmsubscn->max_align - 1) 99da0c48c4Sopenharmony_ci & ~(asmsubscn->max_align - 1)); 100da0c48c4Sopenharmony_ci 101da0c48c4Sopenharmony_ci /* Update the offset for this subsection. This field now 102da0c48c4Sopenharmony_ci stores the offset of the first by in this subsection. */ 103da0c48c4Sopenharmony_ci asmsubscn->offset = offset; 104da0c48c4Sopenharmony_ci 105da0c48c4Sopenharmony_ci /* Note that the content list is circular. */ 106da0c48c4Sopenharmony_ci if (content != NULL) 107da0c48c4Sopenharmony_ci do 108da0c48c4Sopenharmony_ci { 109da0c48c4Sopenharmony_ci Elf_Data *newdata = elf_newdata (scn); 110da0c48c4Sopenharmony_ci 111da0c48c4Sopenharmony_ci if (newdata == NULL) 112da0c48c4Sopenharmony_ci { 113da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_LIBELF); 114da0c48c4Sopenharmony_ci return -1; 115da0c48c4Sopenharmony_ci } 116da0c48c4Sopenharmony_ci 117da0c48c4Sopenharmony_ci newdata->d_buf = content->data; 118da0c48c4Sopenharmony_ci newdata->d_type = ELF_T_BYTE; 119da0c48c4Sopenharmony_ci newdata->d_size = content->len; 120da0c48c4Sopenharmony_ci newdata->d_off = offset; 121da0c48c4Sopenharmony_ci newdata->d_align = first ? asmsubscn->max_align : 1; 122da0c48c4Sopenharmony_ci 123da0c48c4Sopenharmony_ci offset += content->len; 124da0c48c4Sopenharmony_ci } 125da0c48c4Sopenharmony_ci while ((content = content->next) != asmsubscn->content); 126da0c48c4Sopenharmony_ci } 127da0c48c4Sopenharmony_ci while ((asmsubscn = asmsubscn->subnext) != NULL); 128da0c48c4Sopenharmony_ci } 129da0c48c4Sopenharmony_ci 130da0c48c4Sopenharmony_ci 131da0c48c4Sopenharmony_ci /* Create the symbol table if necessary. */ 132da0c48c4Sopenharmony_ci if (ctx->nsymbol_tab > 0) 133da0c48c4Sopenharmony_ci { 134da0c48c4Sopenharmony_ci /* Create the symbol table and string table section names. */ 135da0c48c4Sopenharmony_ci symscn_strent = dwelf_strtab_add_len (ctx->section_strtab, ".symtab", 8); 136da0c48c4Sopenharmony_ci strscn_strent = dwelf_strtab_add_len (ctx->section_strtab, ".strtab", 8); 137da0c48c4Sopenharmony_ci 138da0c48c4Sopenharmony_ci /* Create the symbol string table section. */ 139da0c48c4Sopenharmony_ci Elf_Scn *strscn = elf_newscn (ctx->out.elf); 140da0c48c4Sopenharmony_ci strtabdata = elf_newdata (strscn); 141da0c48c4Sopenharmony_ci shdr = gelf_getshdr (strscn, &shdr_mem); 142da0c48c4Sopenharmony_ci if (strtabdata == NULL || shdr == NULL) 143da0c48c4Sopenharmony_ci { 144da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_LIBELF); 145da0c48c4Sopenharmony_ci return -1; 146da0c48c4Sopenharmony_ci } 147da0c48c4Sopenharmony_ci strscnndx = elf_ndxscn (strscn); 148da0c48c4Sopenharmony_ci 149da0c48c4Sopenharmony_ci dwelf_strtab_finalize (ctx->symbol_strtab, strtabdata); 150da0c48c4Sopenharmony_ci 151da0c48c4Sopenharmony_ci shdr->sh_type = SHT_STRTAB; 152da0c48c4Sopenharmony_ci assert (shdr->sh_entsize == 0); 153da0c48c4Sopenharmony_ci 154da0c48c4Sopenharmony_ci (void) gelf_update_shdr (strscn, shdr); 155da0c48c4Sopenharmony_ci 156da0c48c4Sopenharmony_ci /* Create the symbol table section. */ 157da0c48c4Sopenharmony_ci Elf_Scn *symscn = elf_newscn (ctx->out.elf); 158da0c48c4Sopenharmony_ci data = elf_newdata (symscn); 159da0c48c4Sopenharmony_ci shdr = gelf_getshdr (symscn, &shdr_mem); 160da0c48c4Sopenharmony_ci if (data == NULL || shdr == NULL) 161da0c48c4Sopenharmony_ci { 162da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_LIBELF); 163da0c48c4Sopenharmony_ci return -1; 164da0c48c4Sopenharmony_ci } 165da0c48c4Sopenharmony_ci symscnndx = elf_ndxscn (symscn); 166da0c48c4Sopenharmony_ci 167da0c48c4Sopenharmony_ci /* We know how many symbols there will be in the symbol table. */ 168da0c48c4Sopenharmony_ci data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM, 169da0c48c4Sopenharmony_ci ctx->nsymbol_tab + 1, EV_CURRENT); 170da0c48c4Sopenharmony_ci symtab = malloc (data->d_size); 171da0c48c4Sopenharmony_ci if (symtab == NULL) 172da0c48c4Sopenharmony_ci return -1; 173da0c48c4Sopenharmony_ci data->d_buf = symtab; 174da0c48c4Sopenharmony_ci data->d_type = ELF_T_SYM; 175da0c48c4Sopenharmony_ci data->d_off = 0; 176da0c48c4Sopenharmony_ci 177da0c48c4Sopenharmony_ci /* Clear the first entry. */ 178da0c48c4Sopenharmony_ci GElf_Sym syment; 179da0c48c4Sopenharmony_ci memset (&syment, '\0', sizeof (syment)); 180da0c48c4Sopenharmony_ci (void) gelf_update_sym (data, 0, &syment); 181da0c48c4Sopenharmony_ci 182da0c48c4Sopenharmony_ci /* Iterate over the symbol table. */ 183da0c48c4Sopenharmony_ci void *runp = NULL; 184da0c48c4Sopenharmony_ci int ptr_local = 1; /* Start with index 1; zero remains unused. */ 185da0c48c4Sopenharmony_ci int ptr_nonlocal = ctx->nsymbol_tab; 186da0c48c4Sopenharmony_ci uint32_t *xshndx = NULL; 187da0c48c4Sopenharmony_ci AsmSym_t *sym; 188da0c48c4Sopenharmony_ci while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL) 189da0c48c4Sopenharmony_ci if (asm_emit_symbol_p (dwelf_strent_str (sym->strent))) 190da0c48c4Sopenharmony_ci { 191da0c48c4Sopenharmony_ci assert (ptr_local <= ptr_nonlocal); 192da0c48c4Sopenharmony_ci 193da0c48c4Sopenharmony_ci syment.st_name = dwelf_strent_off (sym->strent); 194da0c48c4Sopenharmony_ci syment.st_info = GELF_ST_INFO (sym->binding, sym->type); 195da0c48c4Sopenharmony_ci syment.st_other = 0; 196da0c48c4Sopenharmony_ci syment.st_value = sym->scn->offset + sym->offset; 197da0c48c4Sopenharmony_ci syment.st_size = sym->size; 198da0c48c4Sopenharmony_ci 199da0c48c4Sopenharmony_ci /* Add local symbols at the beginning, the other from 200da0c48c4Sopenharmony_ci the end. */ 201da0c48c4Sopenharmony_ci int ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--; 202da0c48c4Sopenharmony_ci 203da0c48c4Sopenharmony_ci /* Determine the section index. We have to handle the 204da0c48c4Sopenharmony_ci overflow correctly. */ 205da0c48c4Sopenharmony_ci Elf_Scn *scn = (sym->scn->subsection_id == 0 206da0c48c4Sopenharmony_ci ? sym->scn->data.main.scn 207da0c48c4Sopenharmony_ci : sym->scn->data.up->data.main.scn); 208da0c48c4Sopenharmony_ci 209da0c48c4Sopenharmony_ci Elf32_Word ndx; 210da0c48c4Sopenharmony_ci if (unlikely (scn == ASM_ABS_SCN)) 211da0c48c4Sopenharmony_ci ndx = SHN_ABS; 212da0c48c4Sopenharmony_ci else if (unlikely (scn == ASM_COM_SCN)) 213da0c48c4Sopenharmony_ci ndx = SHN_COMMON; 214da0c48c4Sopenharmony_ci else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE)) 215da0c48c4Sopenharmony_ci { 216da0c48c4Sopenharmony_ci if (unlikely (xshndx == NULL)) 217da0c48c4Sopenharmony_ci { 218da0c48c4Sopenharmony_ci /* The extended section index section does not yet 219da0c48c4Sopenharmony_ci exist. */ 220da0c48c4Sopenharmony_ci Elf_Scn *xndxscn; 221da0c48c4Sopenharmony_ci 222da0c48c4Sopenharmony_ci xndxscn = elf_newscn (ctx->out.elf); 223da0c48c4Sopenharmony_ci xndxdata = elf_newdata (xndxscn); 224da0c48c4Sopenharmony_ci shdr = gelf_getshdr (xndxscn, &shdr_mem); 225da0c48c4Sopenharmony_ci if (xndxdata == NULL || shdr == NULL) 226da0c48c4Sopenharmony_ci { 227da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_LIBELF); 228da0c48c4Sopenharmony_ci return -1; 229da0c48c4Sopenharmony_ci } 230da0c48c4Sopenharmony_ci xndxscnndx = elf_ndxscn (xndxscn); 231da0c48c4Sopenharmony_ci 232da0c48c4Sopenharmony_ci shdr->sh_type = SHT_SYMTAB_SHNDX; 233da0c48c4Sopenharmony_ci shdr->sh_entsize = sizeof (Elf32_Word); 234da0c48c4Sopenharmony_ci shdr->sh_addralign = sizeof (Elf32_Word); 235da0c48c4Sopenharmony_ci shdr->sh_link = symscnndx; 236da0c48c4Sopenharmony_ci 237da0c48c4Sopenharmony_ci (void) gelf_update_shdr (xndxscn, shdr); 238da0c48c4Sopenharmony_ci 239da0c48c4Sopenharmony_ci xndxscn_strent = dwelf_strtab_add_len (ctx->section_strtab, 240da0c48c4Sopenharmony_ci ".symtab_shndx", 241da0c48c4Sopenharmony_ci 14); 242da0c48c4Sopenharmony_ci 243da0c48c4Sopenharmony_ci /* Note that using 'elf32_fsize' instead of 244da0c48c4Sopenharmony_ci 'gelf_fsize' here is correct. */ 245da0c48c4Sopenharmony_ci xndxdata->d_size = elf32_fsize (ELF_T_WORD, 246da0c48c4Sopenharmony_ci ctx->nsymbol_tab + 1, 247da0c48c4Sopenharmony_ci EV_CURRENT); 248da0c48c4Sopenharmony_ci xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size); 249da0c48c4Sopenharmony_ci if (xshndx == NULL) 250da0c48c4Sopenharmony_ci return -1; 251da0c48c4Sopenharmony_ci /* Using ELF_T_WORD here relies on the fact that the 252da0c48c4Sopenharmony_ci 32- and 64-bit types are the same size. */ 253da0c48c4Sopenharmony_ci xndxdata->d_type = ELF_T_WORD; 254da0c48c4Sopenharmony_ci xndxdata->d_off = 0; 255da0c48c4Sopenharmony_ci } 256da0c48c4Sopenharmony_ci 257da0c48c4Sopenharmony_ci /* Store the real section index in the extended section 258da0c48c4Sopenharmony_ci index table. */ 259da0c48c4Sopenharmony_ci assert ((size_t) ptr < ctx->nsymbol_tab + 1); 260da0c48c4Sopenharmony_ci xshndx[ptr] = ndx; 261da0c48c4Sopenharmony_ci 262da0c48c4Sopenharmony_ci /* And signal that this happened. */ 263da0c48c4Sopenharmony_ci ndx = SHN_XINDEX; 264da0c48c4Sopenharmony_ci } 265da0c48c4Sopenharmony_ci syment.st_shndx = ndx; 266da0c48c4Sopenharmony_ci 267da0c48c4Sopenharmony_ci /* Remember where we put the symbol. */ 268da0c48c4Sopenharmony_ci sym->symidx = ptr; 269da0c48c4Sopenharmony_ci 270da0c48c4Sopenharmony_ci (void) gelf_update_sym (data, ptr, &syment); 271da0c48c4Sopenharmony_ci } 272da0c48c4Sopenharmony_ci 273da0c48c4Sopenharmony_ci assert (ptr_local == ptr_nonlocal + 1); 274da0c48c4Sopenharmony_ci 275da0c48c4Sopenharmony_ci shdr->sh_type = SHT_SYMTAB; 276da0c48c4Sopenharmony_ci shdr->sh_link = strscnndx; 277da0c48c4Sopenharmony_ci shdr->sh_info = ptr_local; 278da0c48c4Sopenharmony_ci shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT); 279da0c48c4Sopenharmony_ci shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1, 280da0c48c4Sopenharmony_ci EV_CURRENT); 281da0c48c4Sopenharmony_ci 282da0c48c4Sopenharmony_ci (void) gelf_update_shdr (symscn, shdr); 283da0c48c4Sopenharmony_ci } 284da0c48c4Sopenharmony_ci 285da0c48c4Sopenharmony_ci 286da0c48c4Sopenharmony_ci /* Create the section header string table section and fill in the 287da0c48c4Sopenharmony_ci references in the section headers. */ 288da0c48c4Sopenharmony_ci shstrscn = elf_newscn (ctx->out.elf); 289da0c48c4Sopenharmony_ci shstrtabdata = elf_newdata (shstrscn); 290da0c48c4Sopenharmony_ci shdr = gelf_getshdr (shstrscn, &shdr_mem); 291da0c48c4Sopenharmony_ci if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL) 292da0c48c4Sopenharmony_ci { 293da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_LIBELF); 294da0c48c4Sopenharmony_ci return -1; 295da0c48c4Sopenharmony_ci } 296da0c48c4Sopenharmony_ci 297da0c48c4Sopenharmony_ci 298da0c48c4Sopenharmony_ci /* Add the name of the section header string table. */ 299da0c48c4Sopenharmony_ci shstrscn_strent = dwelf_strtab_add_len (ctx->section_strtab, 300da0c48c4Sopenharmony_ci ".shstrtab", 10); 301da0c48c4Sopenharmony_ci 302da0c48c4Sopenharmony_ci dwelf_strtab_finalize (ctx->section_strtab, shstrtabdata); 303da0c48c4Sopenharmony_ci 304da0c48c4Sopenharmony_ci shdr->sh_type = SHT_STRTAB; 305da0c48c4Sopenharmony_ci assert (shdr->sh_entsize == 0); 306da0c48c4Sopenharmony_ci shdr->sh_name = dwelf_strent_off (shstrscn_strent); 307da0c48c4Sopenharmony_ci 308da0c48c4Sopenharmony_ci (void) gelf_update_shdr (shstrscn, shdr); 309da0c48c4Sopenharmony_ci 310da0c48c4Sopenharmony_ci 311da0c48c4Sopenharmony_ci /* Create the section groups. */ 312da0c48c4Sopenharmony_ci if (ctx->groups != NULL) 313da0c48c4Sopenharmony_ci { 314da0c48c4Sopenharmony_ci AsmScnGrp_t *runp = ctx->groups->next; 315da0c48c4Sopenharmony_ci 316da0c48c4Sopenharmony_ci do 317da0c48c4Sopenharmony_ci { 318da0c48c4Sopenharmony_ci Elf_Scn *scn; 319da0c48c4Sopenharmony_ci Elf32_Word *grpdata; 320da0c48c4Sopenharmony_ci 321da0c48c4Sopenharmony_ci scn = runp->scn; 322da0c48c4Sopenharmony_ci assert (scn != NULL); 323da0c48c4Sopenharmony_ci shdr = gelf_getshdr (scn, &shdr_mem); 324da0c48c4Sopenharmony_ci assert (shdr != NULL); 325da0c48c4Sopenharmony_ci 326da0c48c4Sopenharmony_ci data = elf_newdata (scn); 327da0c48c4Sopenharmony_ci if (data == NULL) 328da0c48c4Sopenharmony_ci { 329da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_LIBELF); 330da0c48c4Sopenharmony_ci return -1; 331da0c48c4Sopenharmony_ci } 332da0c48c4Sopenharmony_ci 333da0c48c4Sopenharmony_ci /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize' 334da0c48c4Sopenharmony_ci here. */ 335da0c48c4Sopenharmony_ci data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1, 336da0c48c4Sopenharmony_ci EV_CURRENT); 337da0c48c4Sopenharmony_ci grpdata = data->d_buf = malloc (data->d_size); 338da0c48c4Sopenharmony_ci if (grpdata == NULL) 339da0c48c4Sopenharmony_ci return -1; 340da0c48c4Sopenharmony_ci data->d_type = ELF_T_WORD; 341da0c48c4Sopenharmony_ci data->d_off = 0; 342da0c48c4Sopenharmony_ci data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT); 343da0c48c4Sopenharmony_ci 344da0c48c4Sopenharmony_ci /* The first word of the section is filled with the flag word. */ 345da0c48c4Sopenharmony_ci *grpdata++ = runp->flags; 346da0c48c4Sopenharmony_ci 347da0c48c4Sopenharmony_ci if (runp->members != NULL) 348da0c48c4Sopenharmony_ci { 349da0c48c4Sopenharmony_ci AsmScn_t *member = runp->members->data.main.next_in_group; 350da0c48c4Sopenharmony_ci 351da0c48c4Sopenharmony_ci do 352da0c48c4Sopenharmony_ci { 353da0c48c4Sopenharmony_ci /* Only sections, not subsections, can be registered 354da0c48c4Sopenharmony_ci as member of a group. The subsections get 355da0c48c4Sopenharmony_ci automatically included. */ 356da0c48c4Sopenharmony_ci assert (member->subsection_id == 0); 357da0c48c4Sopenharmony_ci 358da0c48c4Sopenharmony_ci *grpdata++ = elf_ndxscn (member->data.main.scn); 359da0c48c4Sopenharmony_ci } 360da0c48c4Sopenharmony_ci while ((member = member->data.main.next_in_group) 361da0c48c4Sopenharmony_ci != runp->members->data.main.next_in_group); 362da0c48c4Sopenharmony_ci } 363da0c48c4Sopenharmony_ci 364da0c48c4Sopenharmony_ci /* Construct the section header. */ 365da0c48c4Sopenharmony_ci shdr->sh_name = dwelf_strent_off (runp->strent); 366da0c48c4Sopenharmony_ci shdr->sh_type = SHT_GROUP; 367da0c48c4Sopenharmony_ci shdr->sh_flags = 0; 368da0c48c4Sopenharmony_ci shdr->sh_link = symscnndx; 369da0c48c4Sopenharmony_ci /* If the user did not specify a signature we use the initial 370da0c48c4Sopenharmony_ci empty symbol in the symbol table as the signature. */ 371da0c48c4Sopenharmony_ci shdr->sh_info = (runp->signature != NULL 372da0c48c4Sopenharmony_ci ? runp->signature->symidx : 0); 373da0c48c4Sopenharmony_ci 374da0c48c4Sopenharmony_ci (void) gelf_update_shdr (scn, shdr); 375da0c48c4Sopenharmony_ci } 376da0c48c4Sopenharmony_ci while ((runp = runp->next) != ctx->groups->next); 377da0c48c4Sopenharmony_ci } 378da0c48c4Sopenharmony_ci 379da0c48c4Sopenharmony_ci 380da0c48c4Sopenharmony_ci /* Add the name to the symbol section. */ 381da0c48c4Sopenharmony_ci if (likely (symscnndx != 0)) 382da0c48c4Sopenharmony_ci { 383da0c48c4Sopenharmony_ci Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx); 384da0c48c4Sopenharmony_ci 385da0c48c4Sopenharmony_ci shdr = gelf_getshdr (scn, &shdr_mem); 386da0c48c4Sopenharmony_ci 387da0c48c4Sopenharmony_ci shdr->sh_name = dwelf_strent_off (symscn_strent); 388da0c48c4Sopenharmony_ci 389da0c48c4Sopenharmony_ci (void) gelf_update_shdr (scn, shdr); 390da0c48c4Sopenharmony_ci 391da0c48c4Sopenharmony_ci 392da0c48c4Sopenharmony_ci /* Add the name to the string section. */ 393da0c48c4Sopenharmony_ci assert (strscnndx != 0); 394da0c48c4Sopenharmony_ci scn = elf_getscn (ctx->out.elf, strscnndx); 395da0c48c4Sopenharmony_ci 396da0c48c4Sopenharmony_ci shdr = gelf_getshdr (scn, &shdr_mem); 397da0c48c4Sopenharmony_ci 398da0c48c4Sopenharmony_ci shdr->sh_name = dwelf_strent_off (strscn_strent); 399da0c48c4Sopenharmony_ci 400da0c48c4Sopenharmony_ci (void) gelf_update_shdr (scn, shdr); 401da0c48c4Sopenharmony_ci 402da0c48c4Sopenharmony_ci 403da0c48c4Sopenharmony_ci /* Add the name to the extended symbol index section. */ 404da0c48c4Sopenharmony_ci if (xndxscnndx != 0) 405da0c48c4Sopenharmony_ci { 406da0c48c4Sopenharmony_ci scn = elf_getscn (ctx->out.elf, xndxscnndx); 407da0c48c4Sopenharmony_ci 408da0c48c4Sopenharmony_ci shdr = gelf_getshdr (scn, &shdr_mem); 409da0c48c4Sopenharmony_ci 410da0c48c4Sopenharmony_ci shdr->sh_name = dwelf_strent_off (xndxscn_strent); 411da0c48c4Sopenharmony_ci 412da0c48c4Sopenharmony_ci (void) gelf_update_shdr (scn, shdr); 413da0c48c4Sopenharmony_ci } 414da0c48c4Sopenharmony_ci } 415da0c48c4Sopenharmony_ci 416da0c48c4Sopenharmony_ci 417da0c48c4Sopenharmony_ci /* Iterate over the created sections and fill in the names. */ 418da0c48c4Sopenharmony_ci for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext) 419da0c48c4Sopenharmony_ci { 420da0c48c4Sopenharmony_ci shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem); 421da0c48c4Sopenharmony_ci /* This better should not fail. */ 422da0c48c4Sopenharmony_ci assert (shdr != NULL); 423da0c48c4Sopenharmony_ci 424da0c48c4Sopenharmony_ci shdr->sh_name = dwelf_strent_off (asmscn->data.main.strent); 425da0c48c4Sopenharmony_ci 426da0c48c4Sopenharmony_ci /* We now know the maximum alignment. */ 427da0c48c4Sopenharmony_ci shdr->sh_addralign = asmscn->max_align; 428da0c48c4Sopenharmony_ci 429da0c48c4Sopenharmony_ci (void) gelf_update_shdr (asmscn->data.main.scn, shdr); 430da0c48c4Sopenharmony_ci } 431da0c48c4Sopenharmony_ci 432da0c48c4Sopenharmony_ci /* Put the reference to the section header string table in the ELF 433da0c48c4Sopenharmony_ci header. */ 434da0c48c4Sopenharmony_ci ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem); 435da0c48c4Sopenharmony_ci assert (ehdr != NULL); 436da0c48c4Sopenharmony_ci 437da0c48c4Sopenharmony_ci shstrscnndx = elf_ndxscn (shstrscn); 438da0c48c4Sopenharmony_ci if (unlikely (shstrscnndx > SHN_HIRESERVE) 439da0c48c4Sopenharmony_ci || unlikely (shstrscnndx == SHN_XINDEX)) 440da0c48c4Sopenharmony_ci { 441da0c48c4Sopenharmony_ci /* The index of the section header string sectio is too large. */ 442da0c48c4Sopenharmony_ci Elf_Scn *scn = elf_getscn (ctx->out.elf, 0); 443da0c48c4Sopenharmony_ci 444da0c48c4Sopenharmony_ci /* Get the header for the zeroth section. */ 445da0c48c4Sopenharmony_ci shdr = gelf_getshdr (scn, &shdr_mem); 446da0c48c4Sopenharmony_ci /* This better does not fail. */ 447da0c48c4Sopenharmony_ci assert (shdr != NULL); 448da0c48c4Sopenharmony_ci 449da0c48c4Sopenharmony_ci /* The sh_link field of the zeroth section header contains the value. */ 450da0c48c4Sopenharmony_ci shdr->sh_link = shstrscnndx; 451da0c48c4Sopenharmony_ci 452da0c48c4Sopenharmony_ci (void) gelf_update_shdr (scn, shdr); 453da0c48c4Sopenharmony_ci 454da0c48c4Sopenharmony_ci /* This is the sign for the overflow. */ 455da0c48c4Sopenharmony_ci ehdr->e_shstrndx = SHN_XINDEX; 456da0c48c4Sopenharmony_ci } 457da0c48c4Sopenharmony_ci else 458da0c48c4Sopenharmony_ci ehdr->e_shstrndx = elf_ndxscn (shstrscn); 459da0c48c4Sopenharmony_ci 460da0c48c4Sopenharmony_ci if (unlikely (gelf_update_ehdr (ctx->out.elf, ehdr) == 0)) 461da0c48c4Sopenharmony_ci { 462da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_LIBELF); 463da0c48c4Sopenharmony_ci result = -1; 464da0c48c4Sopenharmony_ci } 465da0c48c4Sopenharmony_ci 466da0c48c4Sopenharmony_ci /* Write out the ELF file. */ 467da0c48c4Sopenharmony_ci if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP) < 0)) 468da0c48c4Sopenharmony_ci { 469da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_LIBELF); 470da0c48c4Sopenharmony_ci result = -1; 471da0c48c4Sopenharmony_ci } 472da0c48c4Sopenharmony_ci 473da0c48c4Sopenharmony_ci /* We do not need the section header and symbol string tables anymore. */ 474da0c48c4Sopenharmony_ci free (shstrtabdata->d_buf); 475da0c48c4Sopenharmony_ci if (strtabdata != NULL) 476da0c48c4Sopenharmony_ci free (strtabdata->d_buf); 477da0c48c4Sopenharmony_ci /* We might have allocated the extended symbol table index. */ 478da0c48c4Sopenharmony_ci if (xndxdata != NULL) 479da0c48c4Sopenharmony_ci free (xndxdata->d_buf); 480da0c48c4Sopenharmony_ci 481da0c48c4Sopenharmony_ci /* Free section groups memory. */ 482da0c48c4Sopenharmony_ci AsmScnGrp_t *scngrp = ctx->groups; 483da0c48c4Sopenharmony_ci if (scngrp != NULL) 484da0c48c4Sopenharmony_ci do 485da0c48c4Sopenharmony_ci free (elf_getdata (scngrp->scn, NULL)->d_buf); 486da0c48c4Sopenharmony_ci while ((scngrp = scngrp->next) != ctx->groups); 487da0c48c4Sopenharmony_ci 488da0c48c4Sopenharmony_ci /* Finalize the ELF handling. */ 489da0c48c4Sopenharmony_ci if (unlikely (elf_end (ctx->out.elf)) != 0) 490da0c48c4Sopenharmony_ci { 491da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_LIBELF); 492da0c48c4Sopenharmony_ci result = -1; 493da0c48c4Sopenharmony_ci } 494da0c48c4Sopenharmony_ci 495da0c48c4Sopenharmony_ci /* Free the temporary resources. */ 496da0c48c4Sopenharmony_ci free (symtab); 497da0c48c4Sopenharmony_ci 498da0c48c4Sopenharmony_ci return result; 499da0c48c4Sopenharmony_ci} 500da0c48c4Sopenharmony_ci 501da0c48c4Sopenharmony_ci 502da0c48c4Sopenharmony_ciint 503da0c48c4Sopenharmony_ciasm_end (AsmCtx_t *ctx) 504da0c48c4Sopenharmony_ci{ 505da0c48c4Sopenharmony_ci int result; 506da0c48c4Sopenharmony_ci 507da0c48c4Sopenharmony_ci if (ctx == NULL) 508da0c48c4Sopenharmony_ci /* Something went wrong earlier. */ 509da0c48c4Sopenharmony_ci return -1; 510da0c48c4Sopenharmony_ci 511da0c48c4Sopenharmony_ci result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx); 512da0c48c4Sopenharmony_ci if (result != 0) 513da0c48c4Sopenharmony_ci return result; 514da0c48c4Sopenharmony_ci 515da0c48c4Sopenharmony_ci /* Make the new file globally readable and user/group-writable. */ 516da0c48c4Sopenharmony_ci if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0) 517da0c48c4Sopenharmony_ci { 518da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_CANNOT_CHMOD); 519da0c48c4Sopenharmony_ci return -1; 520da0c48c4Sopenharmony_ci } 521da0c48c4Sopenharmony_ci 522da0c48c4Sopenharmony_ci /* Rename output file. */ 523da0c48c4Sopenharmony_ci if (rename (ctx->tmp_fname, ctx->fname) != 0) 524da0c48c4Sopenharmony_ci { 525da0c48c4Sopenharmony_ci __libasm_seterrno (ASM_E_CANNOT_RENAME); 526da0c48c4Sopenharmony_ci return -1; 527da0c48c4Sopenharmony_ci } 528da0c48c4Sopenharmony_ci 529da0c48c4Sopenharmony_ci /* Free the resources. */ 530da0c48c4Sopenharmony_ci __libasm_finictx (ctx); 531da0c48c4Sopenharmony_ci 532da0c48c4Sopenharmony_ci return 0; 533da0c48c4Sopenharmony_ci} 534da0c48c4Sopenharmony_ci 535da0c48c4Sopenharmony_ci 536da0c48c4Sopenharmony_cistatic void 537da0c48c4Sopenharmony_cifree_section (AsmScn_t *scnp) 538da0c48c4Sopenharmony_ci{ 539da0c48c4Sopenharmony_ci void *oldp; 540da0c48c4Sopenharmony_ci 541da0c48c4Sopenharmony_ci if (scnp->subnext != NULL) 542da0c48c4Sopenharmony_ci free_section (scnp->subnext); 543da0c48c4Sopenharmony_ci 544da0c48c4Sopenharmony_ci struct AsmData *data = scnp->content; 545da0c48c4Sopenharmony_ci if (data != NULL) 546da0c48c4Sopenharmony_ci do 547da0c48c4Sopenharmony_ci { 548da0c48c4Sopenharmony_ci oldp = data; 549da0c48c4Sopenharmony_ci data = data->next; 550da0c48c4Sopenharmony_ci free (oldp); 551da0c48c4Sopenharmony_ci } 552da0c48c4Sopenharmony_ci while (oldp != scnp->content); 553da0c48c4Sopenharmony_ci 554da0c48c4Sopenharmony_ci free (scnp); 555da0c48c4Sopenharmony_ci} 556da0c48c4Sopenharmony_ci 557da0c48c4Sopenharmony_ci 558da0c48c4Sopenharmony_civoid 559da0c48c4Sopenharmony_ciinternal_function 560da0c48c4Sopenharmony_ci__libasm_finictx (AsmCtx_t *ctx) 561da0c48c4Sopenharmony_ci{ 562da0c48c4Sopenharmony_ci /* Iterate through section table and free individual entries. */ 563da0c48c4Sopenharmony_ci AsmScn_t *scn = ctx->section_list; 564da0c48c4Sopenharmony_ci while (scn != NULL) 565da0c48c4Sopenharmony_ci { 566da0c48c4Sopenharmony_ci AsmScn_t *oldp = scn; 567da0c48c4Sopenharmony_ci scn = scn->allnext; 568da0c48c4Sopenharmony_ci free_section (oldp); 569da0c48c4Sopenharmony_ci } 570da0c48c4Sopenharmony_ci 571da0c48c4Sopenharmony_ci /* Free the resources of the symbol table. */ 572da0c48c4Sopenharmony_ci void *runp = NULL; 573da0c48c4Sopenharmony_ci AsmSym_t *sym; 574da0c48c4Sopenharmony_ci while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL) 575da0c48c4Sopenharmony_ci free (sym); 576da0c48c4Sopenharmony_ci asm_symbol_tab_free (&ctx->symbol_tab); 577da0c48c4Sopenharmony_ci 578da0c48c4Sopenharmony_ci 579da0c48c4Sopenharmony_ci /* Free section groups. */ 580da0c48c4Sopenharmony_ci AsmScnGrp_t *scngrp = ctx->groups; 581da0c48c4Sopenharmony_ci if (scngrp != NULL) 582da0c48c4Sopenharmony_ci do 583da0c48c4Sopenharmony_ci { 584da0c48c4Sopenharmony_ci AsmScnGrp_t *oldp = scngrp; 585da0c48c4Sopenharmony_ci 586da0c48c4Sopenharmony_ci scngrp = scngrp->next; 587da0c48c4Sopenharmony_ci free (oldp); 588da0c48c4Sopenharmony_ci } 589da0c48c4Sopenharmony_ci while (scngrp != ctx->groups); 590da0c48c4Sopenharmony_ci 591da0c48c4Sopenharmony_ci 592da0c48c4Sopenharmony_ci if (unlikely (ctx->textp)) 593da0c48c4Sopenharmony_ci { 594da0c48c4Sopenharmony_ci /* Close the stream. */ 595da0c48c4Sopenharmony_ci fclose (ctx->out.file); 596da0c48c4Sopenharmony_ci } 597da0c48c4Sopenharmony_ci else 598da0c48c4Sopenharmony_ci { 599da0c48c4Sopenharmony_ci /* Close the output file. */ 600da0c48c4Sopenharmony_ci /* XXX We should test for errors here but what would we do if we'd 601da0c48c4Sopenharmony_ci find any. */ 602da0c48c4Sopenharmony_ci (void) close (ctx->fd); 603da0c48c4Sopenharmony_ci 604da0c48c4Sopenharmony_ci /* And the string tables. */ 605da0c48c4Sopenharmony_ci dwelf_strtab_free (ctx->section_strtab); 606da0c48c4Sopenharmony_ci dwelf_strtab_free (ctx->symbol_strtab); 607da0c48c4Sopenharmony_ci } 608da0c48c4Sopenharmony_ci 609da0c48c4Sopenharmony_ci /* Initialize the lock. */ 610da0c48c4Sopenharmony_ci rwlock_fini (ctx->lock); 611da0c48c4Sopenharmony_ci 612da0c48c4Sopenharmony_ci /* Finally free the data structure. */ 613da0c48c4Sopenharmony_ci free (ctx); 614da0c48c4Sopenharmony_ci} 615