/* Finalize operations on the assembler context, free all resources.
This program is Open Source software; you can redistribute it and/or
modify it under the terms of the Open Software License version 1.0 as
published by the Open Source Initiative.
You should have received a copy of the Open Software License along
with this program; if not, you may obtain a copy of the Open Software
License version 1.0 from http://www.opensource.org/licenses/osl.php or
by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
3001 King Ranch Road, Ukiah, CA 95482. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#include <error.h>
#include <libintl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <libasmP.h>
#include <libelf.h>
#include <system.h>
static int
text_end (AsmCtx_t *ctx)
{
// XXX Does anything have to be done?
return 0;
}
static int
binary_end (AsmCtx_t *ctx)
{
void *symtab = NULL;
struct Ebl_Strent *symscn_strent = NULL;
struct Ebl_Strent *strscn_strent = NULL;
struct Ebl_Strent *xndxscn_strent = NULL;
Elf_Scn *shstrscn;
struct Ebl_Strent *shstrscn_strent;
size_t shstrscnndx;
size_t symscnndx = 0;
size_t strscnndx = 0;
size_t xndxscnndx = 0;
Elf_Data *data;
Elf_Data *shstrtabdata;
Elf_Data *strtabdata = NULL;
Elf_Data *xndxdata = NULL;
GElf_Shdr shdr_mem;
GElf_Shdr *shdr;
GElf_Ehdr ehdr_mem;
GElf_Ehdr *ehdr;
AsmScn_t *asmscn;
int result = 0;
/* Iterate over the created sections and compute the offsets of the
various subsections and fill in the content. */
for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
{
#if 0
Elf_Scn *scn = elf_getscn (ctx->out.elf, asmscn->data.main.scnndx);
#else
Elf_Scn *scn = asmscn->data.main.scn;
#endif
off_t offset = 0;
AsmScn_t *asmsubscn = asmscn;
do
{
struct AsmData *content = asmsubscn->content;
bool first = true;
offset = ((offset + asmsubscn->max_align - 1)
& ~(asmsubscn->max_align - 1));
/* Update the offset for this subsection. This field now
stores the offset of the first by in this subsection. */
asmsubscn->offset = offset;
/* Note that the content list is circular. */
if (content != NULL)
do
{
Elf_Data *newdata = elf_newdata (scn);
if (newdata == NULL)
error (EXIT_FAILURE, 0,
_("cannot create section for output file: %s"),
elf_errmsg (-1));
newdata->d_buf = content->data;
newdata->d_type = ELF_T_BYTE;
newdata->d_size = content->len;
newdata->d_off = offset;
newdata->d_align = first ? asmsubscn->max_align : 1;
offset += content->len;
}
while ((content = content->next) != asmsubscn->content);
}
while ((asmsubscn = asmsubscn->subnext) != NULL);
}
/* Create the symbol table if necessary. */
if (ctx->nsymbol_tab > 0)
{
Elf_Scn *symscn;
Elf_Scn *strscn;
AsmSym_t *sym;
int ptr_local;
int ptr_nonlocal;
GElf_Sym syment;
uint32_t *xshndx = NULL;
void *runp;
/* Create the symbol table and string table section names. */
symscn_strent = ebl_strtabadd (ctx->section_strtab, ".symtab", 8);
strscn_strent = ebl_strtabadd (ctx->section_strtab, ".strtab", 8);
/* Create the symbol string table section. */
strscn = elf_newscn (ctx->out.elf);
strtabdata = elf_newdata (strscn);
shdr = gelf_getshdr (strscn, &shdr_mem);
if (strtabdata == NULL || shdr == NULL)
error (EXIT_FAILURE, 0, _("cannot create section for output file: %s"),
elf_errmsg (-1));
strscnndx = elf_ndxscn (strscn);
ebl_strtabfinalize (ctx->symbol_strtab, strtabdata);
shdr->sh_type = SHT_STRTAB;
assert (shdr->sh_entsize == 0);
(void) gelf_update_shdr (strscn, shdr);
/* Create the symbol table section. */
symscn = elf_newscn (ctx->out.elf);
data = elf_newdata (symscn);
shdr = gelf_getshdr (symscn, &shdr_mem);
if (data == NULL || shdr == NULL)
error (EXIT_FAILURE, 0, _("cannot create section for output file: %s"),
elf_errmsg (-1));
symscnndx = elf_ndxscn (symscn);
/* We know how many symbols there will be in the symbol table. */
data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM,
ctx->nsymbol_tab + 1, EV_CURRENT);
symtab = malloc (data->d_size);
if (symtab == NULL)
return -1;
data->d_buf = symtab;
data->d_type = ELF_T_SYM;
data->d_off = 0;
/* Clear the first entry. */
memset (&syment, '\0', sizeof (syment));
(void) gelf_update_sym (data, 0, &syment);
/* Iterate over the symbol table. */
runp = NULL;
ptr_local = 1; /* Start with index 1; zero remains unused. */
ptr_nonlocal = ctx->nsymbol_tab;
while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
if (asm_emit_symbol_p (ebl_string (sym->strent)))
{
int ptr;
Elf32_Word ndx;
Elf_Scn *scn;
assert (ptr_local <= ptr_nonlocal);
syment.st_name = ebl_strtaboffset (sym->strent);
syment.st_info = GELF_ST_INFO (sym->binding, sym->type);
syment.st_other = 0;
syment.st_value = sym->scn->offset + sym->offset;
syment.st_size = sym->size;
/* Add local symbols at the beginning, the other from
the end. */
ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--;
/* Determine the section index. We have to handle the
overflow correctly. */
scn = (sym->scn->subsection_id == 0
? sym->scn->data.main.scn
: sym->scn->data.up->data.main.scn);
if (unlikely (scn == ASM_ABS_SCN))
ndx = SHN_ABS;
else if (unlikely (scn == ASM_COM_SCN))
ndx = SHN_COMMON;
else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE))
{
if (unlikely (xshndx == NULL))
{
/* The extended section index section does not yet
exist. */
Elf_Scn *xndxscn;
size_t symscnndx = elf_ndxscn (symscn);
xndxscn = elf_newscn (ctx->out.elf);
xndxdata = elf_newdata (xndxscn);
shdr = gelf_getshdr (xndxscn, &shdr_mem);
if (xndxdata == NULL || shdr == NULL)
error (EXIT_FAILURE, 0, _("\
cannot create extended section index table: %s"),
elf_errmsg (-1));
xndxscnndx = elf_ndxscn (xndxscn);
shdr->sh_type = SHT_SYMTAB_SHNDX;
shdr->sh_entsize = sizeof (Elf32_Word);
shdr->sh_addralign = sizeof (Elf32_Word);
shdr->sh_link = symscnndx;
(void) gelf_update_shdr (xndxscn, shdr);
xndxscn_strent = ebl_strtabadd (ctx->section_strtab,
".symtab_shndx", 14);
/* Note that using 'elf32_fsize' instead of
'gelf_fsize' here is correct. */
xndxdata->d_size = elf32_fsize (ELF_T_WORD,
ctx->nsymbol_tab + 1,
EV_CURRENT);
xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size);
if (xshndx == NULL)
return -1;
/* Using ELF_T_WORD here relies on the fact that the
32- and 64-bit types are the same size. */
xndxdata->d_type = ELF_T_WORD;
xndxdata->d_off = 0;
}
/* Store the real section index in the extended setion
index table. */
assert ((size_t) ptr < ctx->nsymbol_tab + 1);
xshndx[ptr] = ndx;
/* And signal that this happened. */
ndx = SHN_XINDEX;
}
syment.st_shndx = ndx;
/* Remember where we put the symbol. */
sym->symidx = ptr;
(void) gelf_update_sym (data, ptr, &syment);
}
assert (ptr_local == ptr_nonlocal + 1);
shdr->sh_type = SHT_SYMTAB;
shdr->sh_link = strscnndx;
shdr->sh_info = ptr_local;
shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT);
shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1,
EV_CURRENT);
(void) gelf_update_shdr (symscn, shdr);
}
/* Create the sect