in contrib/elftoolchain/elfcopy/main.c [218:467]
static int copy_from_tempfile(const char *src, const char *dst,
int infd, int *outfd, int in_place);
static void create_file(struct elfcopy *ecp, const char *src,
const char *dst);
static void elfcopy_main(struct elfcopy *ecp, int argc, char **argv);
static void elfcopy_usage(void);
static void mcs_main(struct elfcopy *ecp, int argc, char **argv);
static void mcs_usage(void);
static void parse_sec_address_op(struct elfcopy *ecp, int optnum,
const char *optname, char *s);
static void parse_sec_flags(struct sec_action *sac, char *s);
static void parse_symlist_file(struct elfcopy *ecp, const char *fn,
unsigned int op);
static void print_version(void);
static void set_input_target(struct elfcopy *ecp, const char *target_name);
static void set_osabi(struct elfcopy *ecp, const char *abi);
static void set_output_target(struct elfcopy *ecp, const char *target_name);
static void strip_main(struct elfcopy *ecp, int argc, char **argv);
static void strip_usage(void);
/*
* An ELF object usually has a structure described by the
* diagram below.
* _____________
* | |
* | NULL | <- always a SHT_NULL section
* |_____________|
* | |
* | .interp |
* |_____________|
* | |
* | ... |
* |_____________|
* | |
* | .text |
* |_____________|
* | |
* | ... |
* |_____________|
* | |
* | .comment | <- above(include) this: normal sections
* |_____________|
* | |
* | add sections| <- unloadable sections added by --add-section
* |_____________|
* | |
* | .shstrtab | <- section name string table
* |_____________|
* | |
* | shdrs | <- section header table
* |_____________|
* | |
* | .symtab | <- symbol table, if any
* |_____________|
* | |
* | .strtab | <- symbol name string table, if any
* |_____________|
* | |
* | .rel.text | <- relocation info for .o files.
* |_____________|
*/
void
create_elf(struct elfcopy *ecp)
{
struct section *shtab;
GElf_Ehdr ieh;
GElf_Ehdr oeh;
size_t ishnum;
ecp->flags |= SYMTAB_INTACT;
ecp->flags &= ~SYMTAB_EXIST;
/* Create EHDR. */
if (gelf_getehdr(ecp->ein, &ieh) == NULL)
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
elf_errmsg(-1));
if ((ecp->iec = gelf_getclass(ecp->ein)) == ELFCLASSNONE)
errx(EXIT_FAILURE, "getclass() failed: %s",
elf_errmsg(-1));
if (ecp->oec == ELFCLASSNONE)
ecp->oec = ecp->iec;
if (ecp->oed == ELFDATANONE)
ecp->oed = ieh.e_ident[EI_DATA];
if (gelf_newehdr(ecp->eout, ecp->oec) == NULL)
errx(EXIT_FAILURE, "gelf_newehdr failed: %s",
elf_errmsg(-1));
if (gelf_getehdr(ecp->eout, &oeh) == NULL)
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
elf_errmsg(-1));
memcpy(oeh.e_ident, ieh.e_ident, sizeof(ieh.e_ident));
oeh.e_ident[EI_CLASS] = ecp->oec;
oeh.e_ident[EI_DATA] = ecp->oed;
if (ecp->abi != -1)
oeh.e_ident[EI_OSABI] = ecp->abi;
oeh.e_flags = ieh.e_flags;
oeh.e_machine = ieh.e_machine;
oeh.e_type = ieh.e_type;
oeh.e_entry = ieh.e_entry;
oeh.e_version = ieh.e_version;
ecp->flags &= ~(EXECUTABLE | DYNAMIC | RELOCATABLE);
if (ieh.e_type == ET_EXEC)
ecp->flags |= EXECUTABLE;
else if (ieh.e_type == ET_DYN)
ecp->flags |= DYNAMIC;
else if (ieh.e_type == ET_REL)
ecp->flags |= RELOCATABLE;
else
errx(EXIT_FAILURE, "unsupported e_type");
if (!elf_getshnum(ecp->ein, &ishnum))
errx(EXIT_FAILURE, "elf_getshnum failed: %s",
elf_errmsg(-1));
if (ishnum > 0 && (ecp->secndx = calloc(ishnum,
sizeof(*ecp->secndx))) == NULL)
err(EXIT_FAILURE, "calloc failed");
/* Read input object program header. */
setup_phdr(ecp);
/*
* Scan of input sections: we iterate through sections from input
* object, skip sections need to be stripped, allot Elf_Scn and
* create internal section structure for sections we want.
* (i.e., determine output sections)
*/
create_scn(ecp);
/* Apply section address changes, if any. */
adjust_addr(ecp);
/*
* Determine if the symbol table needs to be changed based on
* command line options.
*/
if (ecp->strip == STRIP_DEBUG ||
ecp->strip == STRIP_UNNEEDED ||
ecp->flags & WEAKEN_ALL ||
ecp->flags & LOCALIZE_HIDDEN ||
ecp->flags & DISCARD_LOCAL ||
ecp->flags & DISCARD_LLABEL ||
ecp->prefix_sym != NULL ||
!STAILQ_EMPTY(&ecp->v_symop))
ecp->flags &= ~SYMTAB_INTACT;
/*
* Create symbol table. Symbols are filtered or stripped according to
* command line args specified by user, and later updated for the new
* layout of sections in the output object.
*/
if ((ecp->flags & SYMTAB_EXIST) != 0)
create_symtab(ecp);
/*
* First processing of output sections: at this stage we copy the
* content of each section from input to output object. Section
* content will be modified and printed (mcs) if need. Also content of
* relocation section probably will be filtered and updated according
* to symbol table changes.
*/
copy_content(ecp);
/*
* Write the underlying ehdr. Note that it should be called
* before elf_setshstrndx() since it will overwrite e->e_shstrndx.
*/
if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
elf_errmsg(-1));
/*
* Second processing of output sections: Update section headers.
* At this stage we set name string index, update st_link and st_info
* for output sections.
*/
update_shdr(ecp, 1);
/* Renew oeh to get the updated e_shstrndx. */
if (gelf_getehdr(ecp->eout, &oeh) == NULL)
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
elf_errmsg(-1));
/*
* Insert SHDR table into the internal section list as a "pseudo"
* section, so later it will get sorted and resynced just as "normal"
* sections.
*
* Under FreeBSD, Binutils objcopy always put the section header
* at the end of all the sections. We want to do the same here.
*
* However, note that the behaviour is still different with Binutils:
* elfcopy checks the FreeBSD OSABI tag to tell whether it needs to
* move the section headers, while Binutils is probably configured
* this way when it's compiled on FreeBSD.
*/
if (oeh.e_ident[EI_OSABI] == ELFOSABI_FREEBSD)
shtab = insert_shtab(ecp, 1);
else
shtab = insert_shtab(ecp, 0);
/*
* Resync section offsets in the output object. This is needed
* because probably sections are modified or new sections are added,
* as a result overlap/gap might appears.
*/
resync_sections(ecp);
/* Store SHDR offset in EHDR. */
oeh.e_shoff = shtab->off;
/* Put program header table immediately after the Elf header. */
if (ecp->ophnum > 0) {
oeh.e_phoff = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT);
if (oeh.e_phoff == 0)
errx(EXIT_FAILURE, "gelf_fsize() failed: %s",
elf_errmsg(-1));
}
/*
* Update ELF object entry point if requested.
*/
if (ecp->change_addr != 0)
oeh.e_entry += ecp->change_addr;
if (ecp->flags & SET_START)
oeh.e_entry = ecp->set_start;
if (ecp->change_start != 0)
oeh.e_entry += ecp->change_start;
/*
* Update ehdr again before we call elf_update(), since we
* modified e_shoff and e_phoff.
*/
if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
elf_errmsg(-1));
if (ecp->ophnum > 0)
copy_phdr(ecp);
/* Write out the output elf object. */
if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
errx(EXIT_FAILURE, "elf_update() failed: %s",
elf_errmsg(-1));
/* Release allocated resource. */
free_elf(ecp);
}