Path: blob/main/contrib/elftoolchain/elfcopy/sections.c
39562 views
/*-1* Copyright (c) 2007-2011,2014 Kai Wang2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/param.h>27#include <sys/stat.h>28#include <err.h>29#include <libgen.h>30#include <stdbool.h>31#include <stdio.h>32#include <stdlib.h>33#include <string.h>3435#include "elfcopy.h"3637ELFTC_VCSID("$Id: sections.c 3758 2019-06-28 01:16:50Z emaste $");3839static void add_gnu_debuglink(struct elfcopy *ecp);40static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc);41static void check_section_rename(struct elfcopy *ecp, struct section *s);42static void filter_reloc(struct elfcopy *ecp, struct section *s);43static int get_section_flags(struct elfcopy *ecp, const char *name);44static void insert_sections(struct elfcopy *ecp);45static int is_append_section(struct elfcopy *ecp, const char *name);46static int is_compress_section(struct elfcopy *ecp, const char *name);47static int is_debug_section(const char *name);48static int is_dwo_section(const char *name);49static int is_modify_section(struct elfcopy *ecp, const char *name);50static int is_print_section(struct elfcopy *ecp, const char *name);51static void modify_section(struct elfcopy *ecp, struct section *s);52static void pad_section(struct elfcopy *ecp, struct section *s);53static void print_data(const char *d, size_t sz);54static void print_section(struct section *s);55static void *read_section(struct section *s, size_t *size);56static void set_shstrtab(struct elfcopy *ecp);57static void update_reloc(struct elfcopy *ecp, struct section *s);58static void update_section_group(struct elfcopy *ecp, struct section *s);5960int61is_remove_section(struct elfcopy *ecp, const char *name)62{6364/* Always keep section name table */65if (strcmp(name, ".shstrtab") == 0)66return 0;67if (strcmp(name, ".symtab") == 0 ||68strcmp(name, ".strtab") == 0) {69if (ecp->strip == STRIP_ALL && lookup_symop_list(70ecp, NULL, SYMOP_KEEP) == NULL)71return (1);72else73return (0);74}7576if (ecp->strip == STRIP_DWO && is_dwo_section(name))77return (1);78if (ecp->strip == STRIP_NONDWO && !is_dwo_section(name))79return (1);8081if (is_debug_section(name)) {82if (ecp->strip == STRIP_ALL ||83ecp->strip == STRIP_DEBUG ||84ecp->strip == STRIP_UNNEEDED ||85(ecp->flags & DISCARD_LOCAL))86return (1);87if (ecp->strip == STRIP_NONDEBUG)88return (0);89}9091if ((ecp->flags & SEC_REMOVE) || (ecp->flags & SEC_COPY)) {92struct sec_action *sac;9394sac = lookup_sec_act(ecp, name, 0);95if ((ecp->flags & SEC_REMOVE) && sac != NULL && sac->remove)96return (1);97if ((ecp->flags & SEC_COPY) && (sac == NULL || !sac->copy))98return (1);99}100101return (0);102}103104/*105* Relocation section needs to be removed if the section it applies to106* will be removed.107*/108int109is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info)110{111const char *name;112GElf_Shdr ish;113Elf_Scn *is;114size_t indx;115int elferr;116117if (elf_getshstrndx(ecp->ein, &indx) == 0)118errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",119elf_errmsg(-1));120121is = elf_getscn(ecp->ein, sh_info);122if (is != NULL) {123if (gelf_getshdr(is, &ish) == NULL)124errx(EXIT_FAILURE, "gelf_getshdr failed: %s",125elf_errmsg(-1));126if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) ==127NULL)128errx(EXIT_FAILURE, "elf_strptr failed: %s",129elf_errmsg(-1));130if (is_remove_section(ecp, name))131return (1);132else133return (0);134}135elferr = elf_errno();136if (elferr != 0)137errx(EXIT_FAILURE, "elf_nextscn failed: %s",138elf_errmsg(elferr));139140/* Remove reloc section if we can't find the target section. */141return (1);142}143144static int145is_append_section(struct elfcopy *ecp, const char *name)146{147struct sec_action *sac;148149sac = lookup_sec_act(ecp, name, 0);150if (sac != NULL && sac->append != 0 && sac->string != NULL)151return (1);152153return (0);154}155156static int157is_compress_section(struct elfcopy *ecp, const char *name)158{159struct sec_action *sac;160161sac = lookup_sec_act(ecp, name, 0);162if (sac != NULL && sac->compress != 0)163return (1);164165return (0);166}167168static void169check_section_rename(struct elfcopy *ecp, struct section *s)170{171struct sec_action *sac;172char *prefix;173size_t namelen;174175if (s->pseudo)176return;177178sac = lookup_sec_act(ecp, s->name, 0);179if (sac != NULL && sac->rename)180s->name = sac->newname;181182if (!strcmp(s->name, ".symtab") ||183!strcmp(s->name, ".strtab") ||184!strcmp(s->name, ".shstrtab"))185return;186187prefix = NULL;188if (s->loadable && ecp->prefix_alloc != NULL)189prefix = ecp->prefix_alloc;190else if (ecp->prefix_sec != NULL)191prefix = ecp->prefix_sec;192193if (prefix != NULL) {194namelen = strlen(s->name) + strlen(prefix) + 1;195if ((s->newname = malloc(namelen)) == NULL)196err(EXIT_FAILURE, "malloc failed");197snprintf(s->newname, namelen, "%s%s", prefix, s->name);198s->name = s->newname;199}200}201202static int203get_section_flags(struct elfcopy *ecp, const char *name)204{205struct sec_action *sac;206207sac = lookup_sec_act(ecp, name, 0);208if (sac != NULL && sac->flags)209return sac->flags;210211return (0);212}213214/*215* Determine whether the section are debugging section.216* According to libbfd, debugging sections are recognized217* only by name.218*/219static int220is_debug_section(const char *name)221{222const char *dbg_sec[] = {223".apple_",224".debug",225".gnu.linkonce.wi.",226".line",227".stab",228NULL229};230const char **p;231232for(p = dbg_sec; *p; p++) {233if (strncmp(name, *p, strlen(*p)) == 0)234return (1);235}236237return (0);238}239240static int241is_dwo_section(const char *name)242{243size_t len;244245if ((len = strlen(name)) > 4 && strcmp(name + len - 4, ".dwo") == 0)246return (1);247return (0);248}249250static int251is_print_section(struct elfcopy *ecp, const char *name)252{253struct sec_action *sac;254255sac = lookup_sec_act(ecp, name, 0);256if (sac != NULL && sac->print != 0)257return (1);258259return (0);260}261262static int263is_modify_section(struct elfcopy *ecp, const char *name)264{265266if (is_append_section(ecp, name) ||267is_compress_section(ecp, name))268return (1);269270return (0);271}272273struct sec_action*274lookup_sec_act(struct elfcopy *ecp, const char *name, int add)275{276struct sec_action *sac;277278if (name == NULL)279return NULL;280281STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {282if (strcmp(name, sac->name) == 0)283return sac;284}285286if (add == 0)287return NULL;288289if ((sac = malloc(sizeof(*sac))) == NULL)290errx(EXIT_FAILURE, "not enough memory");291memset(sac, 0, sizeof(*sac));292sac->name = name;293STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list);294295return (sac);296}297298void299free_sec_act(struct elfcopy *ecp)300{301struct sec_action *sac, *sac_temp;302303STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) {304STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list);305free(sac);306}307}308309void310insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail)311{312struct section *s;313314if (tail || TAILQ_EMPTY(&ecp->v_sec) ||315TAILQ_LAST(&ecp->v_sec, sectionlist)->off <= sec->off) {316TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list);317} else {318TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {319if (sec->off < s->off) {320TAILQ_INSERT_BEFORE(s, sec, sec_list);321break;322}323}324}325326if (sec->pseudo == 0)327ecp->nos++;328}329330/*331* First step of section creation: create scn and internal section332* structure, discard sections to be removed.333*/334void335create_scn(struct elfcopy *ecp)336{337struct section *s;338const char *name;339Elf_Scn *is;340GElf_Shdr ish;341size_t indx;342uint64_t oldndx, newndx;343int elferr, sec_flags, reorder;344bool sections_added;345346/*347* Insert a pseudo section that contains the ELF header348* and program header. Used as reference for section offset349* or load address adjustment.350*/351if ((s = calloc(1, sizeof(*s))) == NULL)352err(EXIT_FAILURE, "calloc failed");353s->off = 0;354s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) +355gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT);356s->align = 1;357s->pseudo = 1;358s->loadable = add_to_inseg_list(ecp, s);359insert_to_sec_list(ecp, s, 0);360361/* Create internal .shstrtab section. */362init_shstrtab(ecp);363364if (elf_getshstrndx(ecp->ein, &indx) == 0)365errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",366elf_errmsg(-1));367368sections_added = false;369reorder = 0;370is = NULL;371while ((is = elf_nextscn(ecp->ein, is)) != NULL) {372if (gelf_getshdr(is, &ish) == NULL)373errx(EXIT_FAILURE, "gelf_getshdr failed: %s",374elf_errmsg(-1));375if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL)376errx(EXIT_FAILURE, "elf_strptr failed: %s",377elf_errmsg(-1));378379/* Skip sections to be removed. */380if (is_remove_section(ecp, name))381continue;382383/*384* Relocation section need to be remove if the section385* it applies will be removed.386*/387if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)388if (ish.sh_info != 0 &&389is_remove_reloc_sec(ecp, ish.sh_info))390continue;391392/*393* Section groups should be removed if symbol table will394* be removed. (section group's signature stored in symbol395* table)396*/397if (ish.sh_type == SHT_GROUP && ecp->strip == STRIP_ALL)398continue;399400/* Get section flags set by user. */401sec_flags = get_section_flags(ecp, name);402403/* Create internal section object. */404if (strcmp(name, ".shstrtab") != 0) {405if ((s = calloc(1, sizeof(*s))) == NULL)406err(EXIT_FAILURE, "calloc failed");407s->name = name;408s->is = is;409s->off = ish.sh_offset;410s->sz = ish.sh_size;411s->align = ish.sh_addralign;412s->type = ish.sh_type;413s->flags = ish.sh_flags;414s->vma = ish.sh_addr;415416/*417* Search program headers to determine whether section418* is loadable, but if user explicitly set section flags419* while neither "load" nor "alloc" is set, we make the420* section unloadable.421*422* Sections in relocatable object is loadable if423* section flag SHF_ALLOC is set.424*/425if (sec_flags &&426(sec_flags & (SF_LOAD | SF_ALLOC)) == 0)427s->loadable = 0;428else {429s->loadable = add_to_inseg_list(ecp, s);430if ((ecp->flags & RELOCATABLE) &&431(ish.sh_flags & SHF_ALLOC))432s->loadable = 1;433}434} else {435/* Assuming .shstrtab is "unloadable". */436s = ecp->shstrtab;437s->off = ish.sh_offset;438}439440oldndx = newndx = SHN_UNDEF;441if (strcmp(name, ".symtab") != 0 &&442strcmp(name, ".strtab") != 0) {443/* Add new sections before .shstrtab if we have one. */444if (!strcmp(name, ".shstrtab")) {445/*446* Add sections specified by --add-section and447* gnu debuglink. we want these sections have448* smaller index than .shstrtab section.449*/450sections_added = true;451if (ecp->debuglink != NULL)452add_gnu_debuglink(ecp);453if (ecp->flags & SEC_ADD)454insert_sections(ecp);455}456if ((s->os = elf_newscn(ecp->eout)) == NULL)457errx(EXIT_FAILURE, "elf_newscn failed: %s",458elf_errmsg(-1));459if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF)460errx(EXIT_FAILURE, "elf_ndxscn failed: %s",461elf_errmsg(-1));462}463if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF)464errx(EXIT_FAILURE, "elf_ndxscn failed: %s",465elf_errmsg(-1));466if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF)467ecp->secndx[oldndx] = newndx;468469/*470* If strip action is STRIP_NONDEBUG(only keep debug),471* change sections type of loadable sections and section472* groups to SHT_NOBITS, and the content of those sections473* will be discarded. However, SHT_NOTE sections should474* be kept.475*/476if (ecp->strip == STRIP_NONDEBUG) {477if (((ish.sh_flags & SHF_ALLOC) ||478(ish.sh_flags & SHF_GROUP)) &&479ish.sh_type != SHT_NOTE)480s->type = SHT_NOBITS;481}482483check_section_rename(ecp, s);484485/* create section header based on input object. */486if (strcmp(name, ".symtab") != 0 &&487strcmp(name, ".strtab") != 0 &&488strcmp(name, ".shstrtab") != 0) {489copy_shdr(ecp, s, NULL, 0, sec_flags);490/*491* elfcopy puts .symtab, .strtab and .shstrtab492* sections in the end of the output object.493* If the input objects have more sections494* after any of these 3 sections, the section495* table will be reordered. section symbols496* should be regenerated for relocations.497*/498if (reorder)499ecp->flags &= ~SYMTAB_INTACT;500} else501reorder = 1;502503if (strcmp(name, ".symtab") == 0) {504ecp->flags |= SYMTAB_EXIST;505ecp->symtab = s;506}507if (strcmp(name, ".strtab") == 0)508ecp->strtab = s;509510insert_to_sec_list(ecp, s, 0);511}512if (!sections_added) {513if (ecp->debuglink != NULL)514add_gnu_debuglink(ecp);515if (ecp->flags & SEC_ADD)516insert_sections(ecp);517}518elferr = elf_errno();519if (elferr != 0)520errx(EXIT_FAILURE, "elf_nextscn failed: %s",521elf_errmsg(elferr));522}523524struct section *525insert_shtab(struct elfcopy *ecp, int tail)526{527struct section *s, *shtab;528GElf_Ehdr ieh;529int nsecs;530531/*532* Treat section header table as a "pseudo" section, insert it533* into section list, so later it will get sorted and resynced534* just as normal sections.535*/536if ((shtab = calloc(1, sizeof(*shtab))) == NULL)537errx(EXIT_FAILURE, "calloc failed");538if (!tail) {539/*540* "shoff" of input object is used as a hint for section541* resync later.542*/543if (gelf_getehdr(ecp->ein, &ieh) == NULL)544errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",545elf_errmsg(-1));546shtab->off = ieh.e_shoff;547} else548shtab->off = 0;549/* Calculate number of sections in the output object. */550nsecs = 0;551TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {552if (!s->pseudo)553nsecs++;554}555/* Remember there is always a null section, so we +1 here. */556shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT);557if (shtab->sz == 0)558errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));559shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8);560shtab->loadable = 0;561shtab->pseudo = 1;562insert_to_sec_list(ecp, shtab, tail);563564return (shtab);565}566567void568copy_content(struct elfcopy *ecp)569{570struct section *s;571572TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {573/* Skip pseudo section. */574if (s->pseudo)575continue;576577/* Skip special sections. */578if (strcmp(s->name, ".symtab") == 0 ||579strcmp(s->name, ".strtab") == 0 ||580strcmp(s->name, ".shstrtab") == 0)581continue;582583/*584* If strip action is STRIP_ALL, relocation info need585* to be stripped. Skip filtering otherwisw.586*/587if (ecp->strip == STRIP_ALL &&588(s->type == SHT_REL || s->type == SHT_RELA))589filter_reloc(ecp, s);590591/*592* The section indices in the SHT_GROUP section needs593* to be updated since we might have stripped some594* sections and changed section numbering.595*/596if (s->type == SHT_GROUP)597update_section_group(ecp, s);598599if (is_modify_section(ecp, s->name))600modify_section(ecp, s);601602copy_data(s);603604/*605* If symbol table is modified, relocation info might606* need update, as symbol index may have changed.607*/608if ((ecp->flags & SYMTAB_INTACT) == 0 &&609(ecp->flags & SYMTAB_EXIST) &&610(s->type == SHT_REL || s->type == SHT_RELA))611update_reloc(ecp, s);612613if (is_print_section(ecp, s->name))614print_section(s);615}616}617618619/*620* Update section group section. The section indices in the SHT_GROUP621* section need update after section numbering changed.622*/623static void624update_section_group(struct elfcopy *ecp, struct section *s)625{626GElf_Shdr ish;627Elf_Data *id;628uint32_t *ws, *wd;629uint64_t n;630size_t ishnum;631int i, j;632633if (!elf_getshnum(ecp->ein, &ishnum))634errx(EXIT_FAILURE, "elf_getshnum failed: %s",635elf_errmsg(-1));636637if (gelf_getshdr(s->is, &ish) == NULL)638errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",639elf_errmsg(-1));640641if ((id = elf_getdata(s->is, NULL)) == NULL)642errx(EXIT_FAILURE, "elf_getdata() failed: %s",643elf_errmsg(-1));644645if (ish.sh_size == 0)646return;647648if (ish.sh_entsize == 0)649ish.sh_entsize = 4;650651ws = id->d_buf;652653/* We only support COMDAT section. */654#ifndef GRP_COMDAT655#define GRP_COMDAT 0x1656#endif657if ((*ws & GRP_COMDAT) == 0)658return;659660if ((s->buf = malloc(ish.sh_size)) == NULL)661err(EXIT_FAILURE, "malloc failed");662663s->sz = ish.sh_size;664665wd = s->buf;666667/* Copy the flag word as-is. */668*wd = *ws;669670/* Update the section indices. */671n = ish.sh_size / ish.sh_entsize;672for(i = 1, j = 1; (uint64_t)i < n; i++) {673if (ws[i] != SHN_UNDEF && ws[i] < ishnum &&674ecp->secndx[ws[i]] != 0)675wd[j++] = ecp->secndx[ws[i]];676else677s->sz -= 4;678}679680s->nocopy = 1;681}682683/*684* Filter relocation entries, only keep those entries whose685* symbol is in the keep list.686*/687static void688filter_reloc(struct elfcopy *ecp, struct section *s)689{690const char *name;691GElf_Shdr ish;692GElf_Rel rel;693GElf_Rela rela;694Elf32_Rel *rel32;695Elf64_Rel *rel64;696Elf32_Rela *rela32;697Elf64_Rela *rela64;698Elf_Data *id;699uint64_t cap, n, nrels, sym;700int elferr, i;701702if (gelf_getshdr(s->is, &ish) == NULL)703errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",704elf_errmsg(-1));705706/* We don't want to touch relocation info for dynamic symbols. */707if ((ecp->flags & SYMTAB_EXIST) == 0) {708/*709* No symbol table in output. If sh_link points to a section710* that exists in the output object, this relocation section711* is for dynamic symbols. Don't touch it.712*/713if (ish.sh_link != 0 && ecp->secndx[ish.sh_link] != 0)714return;715} else {716/* Symbol table exist, check if index equals. */717if (ish.sh_link != elf_ndxscn(ecp->symtab->is))718return;719}720721#define COPYREL(REL, SZ) do { \722if (nrels == 0) { \723if ((REL##SZ = malloc(cap * \724sizeof(*REL##SZ))) == NULL) \725err(EXIT_FAILURE, "malloc failed"); \726} \727if (nrels >= cap) { \728cap *= 2; \729if ((REL##SZ = realloc(REL##SZ, cap * \730sizeof(*REL##SZ))) == NULL) \731err(EXIT_FAILURE, "realloc failed"); \732} \733REL##SZ[nrels].r_offset = REL.r_offset; \734REL##SZ[nrels].r_info = REL.r_info; \735if (s->type == SHT_RELA) \736rela##SZ[nrels].r_addend = rela.r_addend; \737nrels++; \738} while (0)739740nrels = 0;741cap = 4; /* keep list is usually small. */742rel32 = NULL;743rel64 = NULL;744rela32 = NULL;745rela64 = NULL;746if ((id = elf_getdata(s->is, NULL)) == NULL)747errx(EXIT_FAILURE, "elf_getdata() failed: %s",748elf_errmsg(-1));749n = ish.sh_size / ish.sh_entsize;750for(i = 0; (uint64_t)i < n; i++) {751if (s->type == SHT_REL) {752if (gelf_getrel(id, i, &rel) != &rel)753errx(EXIT_FAILURE, "gelf_getrel failed: %s",754elf_errmsg(-1));755sym = GELF_R_SYM(rel.r_info);756} else {757if (gelf_getrela(id, i, &rela) != &rela)758errx(EXIT_FAILURE, "gelf_getrel failed: %s",759elf_errmsg(-1));760sym = GELF_R_SYM(rela.r_info);761}762/*763* If a relocation references a symbol and we are omitting764* either that symbol or the entire symbol table we cannot765* produce valid output, and so just omit the relocation.766* Broken output like this is generally not useful, but some767* uses of elfcopy/strip rely on it - for example, GCC's build768* process uses it to check for build reproducibility by769* stripping objects and comparing them.770*771* Relocations that do not reference a symbol are retained.772*/773if (sym != 0) {774if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0)775continue;776name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is),777sym);778if (name == NULL)779errx(EXIT_FAILURE, "elf_strptr failed: %s",780elf_errmsg(-1));781if (lookup_symop_list(ecp, name, SYMOP_KEEP) == NULL)782continue;783}784if (ecp->oec == ELFCLASS32) {785if (s->type == SHT_REL)786COPYREL(rel, 32);787else788COPYREL(rela, 32);789} else {790if (s->type == SHT_REL)791COPYREL(rel, 64);792else793COPYREL(rela, 64);794}795}796elferr = elf_errno();797if (elferr != 0)798errx(EXIT_FAILURE, "elf_getdata() failed: %s",799elf_errmsg(elferr));800801if (ecp->oec == ELFCLASS32) {802if (s->type == SHT_REL)803s->buf = rel32;804else805s->buf = rela32;806} else {807if (s->type == SHT_REL)808s->buf = rel64;809else810s->buf = rela64;811}812s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL :813ELF_T_RELA), nrels, EV_CURRENT);814s->nocopy = 1;815}816817static void818update_reloc(struct elfcopy *ecp, struct section *s)819{820GElf_Shdr osh;821GElf_Rel rel;822GElf_Rela rela;823Elf_Data *od;824uint64_t n;825int i;826827#define UPDATEREL(REL) do { \828if (gelf_get##REL(od, i, &REL) != &REL) \829errx(EXIT_FAILURE, "gelf_get##REL failed: %s", \830elf_errmsg(-1)); \831REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)], \832GELF_R_TYPE(REL.r_info)); \833if (!gelf_update_##REL(od, i, &REL)) \834errx(EXIT_FAILURE, "gelf_update_##REL failed: %s", \835elf_errmsg(-1)); \836} while(0)837838if (s->sz == 0)839return;840if (gelf_getshdr(s->os, &osh) == NULL)841errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",842elf_errmsg(-1));843/* Only process .symtab reloc info. */844if (osh.sh_link != elf_ndxscn(ecp->symtab->is))845return;846if ((od = elf_getdata(s->os, NULL)) == NULL)847errx(EXIT_FAILURE, "elf_getdata() failed: %s",848elf_errmsg(-1));849n = osh.sh_size / osh.sh_entsize;850for(i = 0; (uint64_t)i < n; i++) {851if (s->type == SHT_REL)852UPDATEREL(rel);853else854UPDATEREL(rela);855}856}857858static void859pad_section(struct elfcopy *ecp, struct section *s)860{861GElf_Shdr osh;862Elf_Data *od;863864if (s == NULL || s->pad_sz == 0)865return;866867if ((s->pad = malloc(s->pad_sz)) == NULL)868err(EXIT_FAILURE, "malloc failed");869memset(s->pad, ecp->fill, s->pad_sz);870871/* Create a new Elf_Data to contain the padding bytes. */872if ((od = elf_newdata(s->os)) == NULL)873errx(EXIT_FAILURE, "elf_newdata() failed: %s",874elf_errmsg(-1));875od->d_align = 1;876od->d_off = s->sz;877od->d_buf = s->pad;878od->d_type = ELF_T_BYTE;879od->d_size = s->pad_sz;880od->d_version = EV_CURRENT;881882/* Update section header. */883if (gelf_getshdr(s->os, &osh) == NULL)884errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",885elf_errmsg(-1));886osh.sh_size = s->sz + s->pad_sz;887if (!gelf_update_shdr(s->os, &osh))888errx(EXIT_FAILURE, "elf_update_shdr failed: %s",889elf_errmsg(-1));890}891892static int893section_type_alignment(int sht, int class)894{895switch (sht)896{897case SHT_DYNAMIC:898case SHT_DYNSYM:899case SHT_FINI_ARRAY:900case SHT_GNU_HASH:901case SHT_INIT_ARRAY:902case SHT_PREINIT_ARRAY:903case SHT_REL:904case SHT_RELA:905case SHT_SYMTAB:906return (class == ELFCLASS64 ? 8 : 4);907case SHT_SUNW_move:908return (8);909case SHT_GNU_LIBLIST:910case SHT_GROUP:911case SHT_HASH:912case SHT_NOTE:913case SHT_SUNW_verdef: /* == SHT_GNU_verdef */914case SHT_SUNW_verneed: /* == SHT_GNU_verneed */915case SHT_SYMTAB_SHNDX:916return (4);917case SHT_SUNW_syminfo:918case SHT_SUNW_versym: /* == SHT_GNU_versym */919return (2);920case SHT_NOBITS:921case SHT_PROGBITS:922case SHT_STRTAB:923case SHT_SUNW_dof:924return (1);925}926return (1);927}928929void930resync_sections(struct elfcopy *ecp)931{932struct section *s, *ps;933GElf_Shdr osh;934uint64_t off;935int first;936int min_alignment;937938ps = NULL;939first = 1;940off = 0;941TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {942if (first) {943off = s->off;944first = 0;945}946947/*948* Ignore TLS sections with load address 0 and without949* content. We don't need to adjust their file offset or950* VMA, only the size matters.951*/952if (s->seg_tls != NULL && s->type == SHT_NOBITS &&953s->off == 0)954continue;955956/* Align section offset. */957if (s->align == 0)958s->align = 1;959min_alignment = section_type_alignment(s->type, ecp->oec);960if (s->align < INT_MAX && (int)s->align < min_alignment) {961warnx("section %s alignment %d increased to %d",962s->name, (int)s->align, min_alignment);963s->align = min_alignment;964}965if (off <= s->off) {966if (!s->loadable || (ecp->flags & RELOCATABLE))967s->off = roundup(off, s->align);968} else {969if (s->loadable && (ecp->flags & RELOCATABLE) == 0)970warnx("moving loadable section %s, "971"is this intentional?", s->name);972s->off = roundup(off, s->align);973}974975/* Calculate next section offset. */976off = s->off;977if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL))978off += s->sz;979980if (s->pseudo) {981ps = NULL;982continue;983}984985/* Count padding bytes added through --pad-to. */986if (s->pad_sz > 0)987off += s->pad_sz;988989/* Update section header accordingly. */990if (gelf_getshdr(s->os, &osh) == NULL)991errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",992elf_errmsg(-1));993osh.sh_addr = s->vma;994osh.sh_addralign = s->align;995osh.sh_offset = s->off;996osh.sh_size = s->sz;997if (!gelf_update_shdr(s->os, &osh))998errx(EXIT_FAILURE, "elf_update_shdr failed: %s",999elf_errmsg(-1));10001001/* Add padding for previous section, if need. */1002if (ps != NULL) {1003if (ps->pad_sz > 0) {1004/* Apply padding added by --pad-to. */1005pad_section(ecp, ps);1006} else if ((ecp->flags & GAP_FILL) &&1007(ps->off + ps->sz < s->off)) {1008/*1009* Fill the gap between sections by padding1010* the section with lower address.1011*/1012ps->pad_sz = s->off - (ps->off + ps->sz);1013pad_section(ecp, ps);1014}1015}10161017ps = s;1018}10191020/* Pad the last section, if need. */1021if (ps != NULL && ps->pad_sz > 0)1022pad_section(ecp, ps);1023}10241025static void1026modify_section(struct elfcopy *ecp, struct section *s)1027{1028struct sec_action *sac;1029size_t srcsz, dstsz, p, len;1030char *b, *c, *d, *src, *end;1031int dupe;10321033src = read_section(s, &srcsz);1034if (src == NULL || srcsz == 0) {1035/* For empty section, we proceed if we need to append. */1036if (!is_append_section(ecp, s->name))1037return;1038}10391040/* Allocate buffer needed for new section data. */1041dstsz = srcsz;1042if (is_append_section(ecp, s->name)) {1043sac = lookup_sec_act(ecp, s->name, 0);1044dstsz += strlen(sac->string) + 1;1045}1046if ((b = malloc(dstsz)) == NULL)1047err(EXIT_FAILURE, "malloc failed");1048s->buf = b;10491050/* Compress section. */1051p = 0;1052if (is_compress_section(ecp, s->name)) {1053end = src + srcsz;1054for(c = src; c < end;) {1055len = 0;1056while(c + len < end && c[len] != '\0')1057len++;1058if (c + len == end) {1059/* XXX should we warn here? */1060strncpy(&b[p], c, len);1061p += len;1062break;1063}1064dupe = 0;1065for (d = b; d < b + p; ) {1066if (strcmp(d, c) == 0) {1067dupe = 1;1068break;1069}1070d += strlen(d) + 1;1071}1072if (!dupe) {1073strncpy(&b[p], c, len);1074b[p + len] = '\0';1075p += len + 1;1076}1077c += len + 1;1078}1079} else {1080memcpy(b, src, srcsz);1081p += srcsz;1082}10831084/* Append section. */1085if (is_append_section(ecp, s->name)) {1086sac = lookup_sec_act(ecp, s->name, 0);1087len = strlen(sac->string);1088strncpy(&b[p], sac->string, len);1089b[p + len] = '\0';1090p += len + 1;1091}10921093s->sz = p;1094s->nocopy = 1;1095}10961097static void1098print_data(const char *d, size_t sz)1099{1100const char *c;11011102for (c = d; c < d + sz; c++) {1103if (*c == '\0')1104putchar('\n');1105else1106putchar(*c);1107}1108}11091110static void1111print_section(struct section *s)1112{1113Elf_Data *id;1114int elferr;11151116if (s->buf != NULL && s->sz > 0) {1117print_data(s->buf, s->sz);1118} else {1119id = NULL;1120while ((id = elf_getdata(s->is, id)) != NULL ||1121(id = elf_rawdata(s->is, id)) != NULL) {1122(void) elf_errno();1123print_data(id->d_buf, id->d_size);1124}1125elferr = elf_errno();1126if (elferr != 0)1127errx(EXIT_FAILURE, "elf_getdata() failed: %s",1128elf_errmsg(elferr));1129}1130putchar('\n');1131}11321133static void *1134read_section(struct section *s, size_t *size)1135{1136Elf_Data *id;1137char *b;1138size_t sz;1139int elferr;11401141sz = 0;1142b = NULL;1143id = NULL;1144while ((id = elf_getdata(s->is, id)) != NULL ||1145(id = elf_rawdata(s->is, id)) != NULL) {1146(void) elf_errno();1147if (b == NULL)1148b = malloc(id->d_size);1149else1150b = realloc(b, sz + id->d_size);1151if (b == NULL)1152err(EXIT_FAILURE, "malloc or realloc failed");11531154memcpy(&b[sz], id->d_buf, id->d_size);1155sz += id->d_size;1156}1157elferr = elf_errno();1158if (elferr != 0)1159errx(EXIT_FAILURE, "elf_getdata() failed: %s",1160elf_errmsg(elferr));11611162*size = sz;11631164return (b);1165}11661167void1168copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy,1169int sec_flags)1170{1171GElf_Shdr ish, osh;11721173if (gelf_getshdr(s->is, &ish) == NULL)1174errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",1175elf_errmsg(-1));1176if (gelf_getshdr(s->os, &osh) == NULL)1177errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",1178elf_errmsg(-1));11791180if (copy)1181(void) memcpy(&osh, &ish, sizeof(ish));1182else {1183osh.sh_type = s->type;1184osh.sh_addr = s->vma;1185osh.sh_offset = s->off;1186osh.sh_size = s->sz;1187osh.sh_link = ish.sh_link;1188osh.sh_info = ish.sh_info;1189osh.sh_addralign = s->align;1190osh.sh_entsize = ish.sh_entsize;11911192if (sec_flags) {1193osh.sh_flags = 0;1194if (sec_flags & SF_ALLOC)1195osh.sh_flags |= SHF_ALLOC;1196if ((sec_flags & SF_READONLY) == 0)1197osh.sh_flags |= SHF_WRITE;1198if (sec_flags & SF_CODE)1199osh.sh_flags |= SHF_EXECINSTR;1200if ((sec_flags & SF_CONTENTS) &&1201s->type == SHT_NOBITS && s->sz > 0) {1202/*1203* Convert SHT_NOBITS section to section with1204* (zero'ed) content on file.1205*/1206osh.sh_type = s->type = SHT_PROGBITS;1207if ((s->buf = calloc(1, s->sz)) == NULL)1208err(EXIT_FAILURE, "malloc failed");1209s->nocopy = 1;1210}1211} else {1212osh.sh_flags = ish.sh_flags;1213/*1214* Newer binutils as(1) emits the section flag1215* SHF_INFO_LINK for relocation sections. elfcopy1216* emits this flag in the output section if it's1217* missing in the input section, to remain compatible1218* with binutils.1219*/1220if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)1221osh.sh_flags |= SHF_INFO_LINK;1222}1223}12241225if (name == NULL)1226add_to_shstrtab(ecp, s->name);1227else1228add_to_shstrtab(ecp, name);12291230if (!gelf_update_shdr(s->os, &osh))1231errx(EXIT_FAILURE, "elf_update_shdr failed: %s",1232elf_errmsg(-1));1233}12341235void1236copy_data(struct section *s)1237{1238Elf_Data *id, *od;1239int elferr;12401241if (s->nocopy && s->buf == NULL)1242return;12431244if ((id = elf_getdata(s->is, NULL)) == NULL) {1245(void) elf_errno();1246if ((id = elf_rawdata(s->is, NULL)) == NULL) {1247elferr = elf_errno();1248if (elferr != 0)1249errx(EXIT_FAILURE, "failed to read section:"1250" %s", s->name);1251return;1252}1253}12541255if ((od = elf_newdata(s->os)) == NULL)1256errx(EXIT_FAILURE, "elf_newdata() failed: %s",1257elf_errmsg(-1));12581259if (s->nocopy) {1260/* Use s->buf as content if s->nocopy is set. */1261od->d_align = id->d_align;1262od->d_off = 0;1263od->d_buf = s->buf;1264od->d_type = id->d_type;1265od->d_size = s->sz;1266od->d_version = id->d_version;1267} else {1268od->d_align = id->d_align;1269od->d_off = id->d_off;1270od->d_buf = id->d_buf;1271od->d_type = id->d_type;1272od->d_size = id->d_size;1273od->d_version = id->d_version;1274}12751276/*1277* Alignment Fixup. libelf does not allow the alignment for1278* Elf_Data descriptor to be set to 0. In this case we workaround1279* it by setting the alignment to 1.1280*1281* According to the ELF ABI, alignment 0 and 1 has the same1282* meaning: the section has no alignment constraints.1283*/1284if (od->d_align == 0)1285od->d_align = 1;1286}12871288struct section *1289create_external_section(struct elfcopy *ecp, const char *name, char *newname,1290void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype,1291uint64_t flags, uint64_t align, uint64_t vma, int loadable)1292{1293struct section *s;1294Elf_Scn *os;1295Elf_Data *od;1296GElf_Shdr osh;12971298if ((os = elf_newscn(ecp->eout)) == NULL)1299errx(EXIT_FAILURE, "elf_newscn() failed: %s",1300elf_errmsg(-1));1301if ((s = calloc(1, sizeof(*s))) == NULL)1302err(EXIT_FAILURE, "calloc failed");1303s->name = name;1304s->newname = newname; /* needs to be free()'ed */1305s->off = off;1306s->sz = size;1307s->vma = vma;1308s->align = align;1309s->loadable = loadable;1310s->is = NULL;1311s->os = os;1312s->type = stype;1313s->nocopy = 1;1314insert_to_sec_list(ecp, s, 1);13151316if (gelf_getshdr(os, &osh) == NULL)1317errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",1318elf_errmsg(-1));1319osh.sh_flags = flags;1320osh.sh_type = s->type;1321osh.sh_addr = s->vma;1322osh.sh_addralign = s->align;1323if (!gelf_update_shdr(os, &osh))1324errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",1325elf_errmsg(-1));1326add_to_shstrtab(ecp, name);13271328if (buf != NULL && size != 0) {1329if ((od = elf_newdata(os)) == NULL)1330errx(EXIT_FAILURE, "elf_newdata() failed: %s",1331elf_errmsg(-1));1332od->d_align = align;1333od->d_off = 0;1334od->d_buf = buf;1335od->d_size = size;1336od->d_type = dtype;1337od->d_version = EV_CURRENT;1338}13391340/*1341* Clear SYMTAB_INTACT, as we probably need to update/add new1342* STT_SECTION symbols into the symbol table.1343*/1344ecp->flags &= ~SYMTAB_INTACT;13451346return (s);1347}13481349/*1350* Insert sections specified by --add-section to the end of section list.1351*/1352static void1353insert_sections(struct elfcopy *ecp)1354{1355struct sec_add *sa;1356struct section *s;1357size_t off;1358uint64_t stype;13591360/* Put these sections in the end of current list. */1361off = 0;1362TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {1363if (s->type != SHT_NOBITS && s->type != SHT_NULL)1364off = s->off + s->sz;1365else1366off = s->off;1367}13681369STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) {13701371/* TODO: Add section header vma/lma, flag changes here */13721373/*1374* The default section type for user added section is1375* SHT_PROGBITS. If the section name match certain patterns,1376* elfcopy will try to set a more appropriate section type.1377* However, data type is always set to ELF_T_BYTE and no1378* translation is performed by libelf.1379*/1380stype = SHT_PROGBITS;1381if (strcmp(sa->name, ".note") == 0 ||1382strncmp(sa->name, ".note.", strlen(".note.")) == 0)1383stype = SHT_NOTE;13841385(void) create_external_section(ecp, sa->name, NULL, sa->content,1386sa->size, off, stype, ELF_T_BYTE, 0, 1, 0, 0);1387}1388}13891390void1391add_to_shstrtab(struct elfcopy *ecp, const char *name)1392{13931394if (elftc_string_table_insert(ecp->shstrtab->strtab, name) == 0)1395errx(EXIT_FAILURE, "elftc_string_table_insert failed");1396}13971398void1399update_shdr(struct elfcopy *ecp, int update_link)1400{1401struct section *s;1402GElf_Shdr osh;1403int elferr;14041405/* Finalize the section name string table (.shstrtab). */1406set_shstrtab(ecp);14071408TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {1409if (s->pseudo)1410continue;14111412if (gelf_getshdr(s->os, &osh) == NULL)1413errx(EXIT_FAILURE, "gelf_getshdr failed: %s",1414elf_errmsg(-1));14151416/* Find section name in string table and set sh_name. */1417osh.sh_name = elftc_string_table_lookup(ecp->shstrtab->strtab,1418s->name);14191420/*1421* sh_link needs to be updated, since the index of the1422* linked section might have changed.1423*/1424if (update_link && osh.sh_link != 0)1425osh.sh_link = ecp->secndx[osh.sh_link];14261427/*1428* sh_info of relocation section links to the section to which1429* its relocation info applies. So it may need update as well.1430*/1431if ((s->type == SHT_REL || s->type == SHT_RELA) &&1432osh.sh_info != 0)1433osh.sh_info = ecp->secndx[osh.sh_info];14341435/*1436* sh_info of SHT_GROUP section needs to point to the correct1437* string in the symbol table.1438*/1439if (s->type == SHT_GROUP && (ecp->flags & SYMTAB_EXIST) &&1440(ecp->flags & SYMTAB_INTACT) == 0)1441osh.sh_info = ecp->symndx[osh.sh_info];14421443if (!gelf_update_shdr(s->os, &osh))1444errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",1445elf_errmsg(-1));1446}1447elferr = elf_errno();1448if (elferr != 0)1449errx(EXIT_FAILURE, "elf_nextscn failed: %s",1450elf_errmsg(elferr));1451}14521453void1454init_shstrtab(struct elfcopy *ecp)1455{1456Elf_Scn *shstrtab;1457GElf_Shdr shdr;1458struct section *s;1459size_t indx, sizehint;14601461if (elf_getshdrstrndx(ecp->ein, &indx) == 0) {1462shstrtab = elf_getscn(ecp->ein, indx);1463if (shstrtab == NULL)1464errx(EXIT_FAILURE, "elf_getscn failed: %s",1465elf_errmsg(-1));1466if (gelf_getshdr(shstrtab, &shdr) != &shdr)1467errx(EXIT_FAILURE, "gelf_getshdr failed: %s",1468elf_errmsg(-1));1469sizehint = shdr.sh_size;1470} else {1471/* Clear the error from elf_getshdrstrndx(3). */1472(void)elf_errno();1473sizehint = 0;1474}14751476if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL)1477err(EXIT_FAILURE, "calloc failed");1478s = ecp->shstrtab;1479s->name = ".shstrtab";1480s->is = NULL;1481s->sz = 0;1482s->align = 1;1483s->loadable = 0;1484s->type = SHT_STRTAB;1485s->vma = 0;1486s->strtab = elftc_string_table_create(sizehint);14871488add_to_shstrtab(ecp, "");1489add_to_shstrtab(ecp, ".symtab");1490add_to_shstrtab(ecp, ".strtab");1491add_to_shstrtab(ecp, ".shstrtab");1492}14931494static void1495set_shstrtab(struct elfcopy *ecp)1496{1497struct section *s;1498Elf_Data *data;1499GElf_Shdr sh;1500const char *image;1501size_t sz;15021503s = ecp->shstrtab;15041505if (s->os == NULL) {1506/* Input object does not contain .shstrtab section */1507if ((s->os = elf_newscn(ecp->eout)) == NULL)1508errx(EXIT_FAILURE, "elf_newscn failed: %s",1509elf_errmsg(-1));1510insert_to_sec_list(ecp, s, 1);1511}15121513if (gelf_getshdr(s->os, &sh) == NULL)1514errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",1515elf_errmsg(-1));1516sh.sh_addr = 0;1517sh.sh_addralign = 1;1518sh.sh_offset = s->off;1519sh.sh_type = SHT_STRTAB;1520sh.sh_flags = 0;1521sh.sh_entsize = 0;1522sh.sh_info = 0;1523sh.sh_link = 0;15241525if ((data = elf_newdata(s->os)) == NULL)1526errx(EXIT_FAILURE, "elf_newdata() failed: %s",1527elf_errmsg(-1));15281529/*1530* If we don't have a symbol table, skip those a few bytes1531* which are reserved for this in the beginning of shstrtab.1532*/1533if (!(ecp->flags & SYMTAB_EXIST)) {1534elftc_string_table_remove(s->strtab, ".symtab");1535elftc_string_table_remove(s->strtab, ".strtab");1536}15371538image = elftc_string_table_image(s->strtab, &sz);1539s->sz = sz;15401541sh.sh_size = sz;1542if (!gelf_update_shdr(s->os, &sh))1543errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",1544elf_errmsg(-1));15451546data->d_align = 1;1547data->d_buf = (void *)(uintptr_t)image;1548data->d_size = sz;1549data->d_off = 0;1550data->d_type = ELF_T_BYTE;1551data->d_version = EV_CURRENT;15521553if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os)))1554errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s",1555elf_errmsg(-1));1556}15571558void1559add_section(struct elfcopy *ecp, const char *arg)1560{1561struct sec_add *sa;1562struct stat sb;1563const char *s, *fn;1564FILE *fp;1565int len;15661567if ((s = strchr(arg, '=')) == NULL)1568errx(EXIT_FAILURE,1569"illegal format for --add-section option");1570if ((sa = malloc(sizeof(*sa))) == NULL)1571err(EXIT_FAILURE, "malloc failed");15721573len = s - arg;1574if ((sa->name = malloc(len + 1)) == NULL)1575err(EXIT_FAILURE, "malloc failed");1576strncpy(sa->name, arg, len);1577sa->name[len] = '\0';15781579fn = s + 1;1580if (stat(fn, &sb) == -1)1581err(EXIT_FAILURE, "stat failed");1582sa->size = sb.st_size;1583if (sa->size > 0) {1584if ((sa->content = malloc(sa->size)) == NULL)1585err(EXIT_FAILURE, "malloc failed");1586if ((fp = fopen(fn, "r")) == NULL)1587err(EXIT_FAILURE, "can not open %s", fn);1588if (fread(sa->content, 1, sa->size, fp) == 0 ||1589ferror(fp))1590err(EXIT_FAILURE, "fread failed");1591fclose(fp);1592} else1593sa->content = NULL;15941595STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);1596ecp->flags |= SEC_ADD;1597}15981599void1600free_sec_add(struct elfcopy *ecp)1601{1602struct sec_add *sa, *sa_temp;16031604STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) {1605STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list);1606free(sa->name);1607free(sa->content);1608free(sa);1609}1610}16111612static void1613add_gnu_debuglink(struct elfcopy *ecp)1614{1615struct sec_add *sa;1616struct stat sb;1617FILE *fp;1618char *fnbase, *buf;1619int crc_off;1620int crc;16211622if (ecp->debuglink == NULL)1623return;16241625/* Read debug file content. */1626if ((sa = malloc(sizeof(*sa))) == NULL)1627err(EXIT_FAILURE, "malloc failed");1628if ((sa->name = strdup(".gnu_debuglink")) == NULL)1629err(EXIT_FAILURE, "strdup failed");1630if (stat(ecp->debuglink, &sb) == -1)1631err(EXIT_FAILURE, "stat failed");1632if (sb.st_size == 0)1633errx(EXIT_FAILURE, "empty debug link target %s",1634ecp->debuglink);1635if ((buf = malloc(sb.st_size)) == NULL)1636err(EXIT_FAILURE, "malloc failed");1637if ((fp = fopen(ecp->debuglink, "r")) == NULL)1638err(EXIT_FAILURE, "can not open %s", ecp->debuglink);1639if (fread(buf, 1, sb.st_size, fp) == 0 ||1640ferror(fp))1641err(EXIT_FAILURE, "fread failed");1642fclose(fp);16431644/* Calculate crc checksum. */1645crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF);1646free(buf);16471648/* Calculate section size and the offset to store crc checksum. */1649if ((fnbase = basename(ecp->debuglink)) == NULL)1650err(EXIT_FAILURE, "basename failed");1651crc_off = roundup(strlen(fnbase) + 1, 4);1652sa->size = crc_off + 4;16531654/* Section content. */1655if ((sa->content = calloc(1, sa->size)) == NULL)1656err(EXIT_FAILURE, "malloc failed");1657strncpy(sa->content, fnbase, strlen(fnbase));1658if (ecp->oed == ELFDATA2LSB) {1659sa->content[crc_off] = crc & 0xFF;1660sa->content[crc_off + 1] = (crc >> 8) & 0xFF;1661sa->content[crc_off + 2] = (crc >> 16) & 0xFF;1662sa->content[crc_off + 3] = crc >> 24;1663} else {1664sa->content[crc_off] = crc >> 24;1665sa->content[crc_off + 1] = (crc >> 16) & 0xFF;1666sa->content[crc_off + 2] = (crc >> 8) & 0xFF;1667sa->content[crc_off + 3] = crc & 0xFF;1668}16691670STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);1671ecp->flags |= SEC_ADD;1672}16731674static uint32_t crctable[256] =1675{16760x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,16770x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,16780x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,16790x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,16800x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,16810x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,16820x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,16830x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,16840x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,16850x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,16860x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,16870x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,16880x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,16890x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,16900x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,16910x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,16920x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,16930x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,16940x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,16950x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,16960x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,16970x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,16980x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,16990x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,17000x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,17010x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,17020x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,17030x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,17040x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,17050x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,17060x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,17070x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,17080xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,17090xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,17100xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,17110xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,17120xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,17130xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,17140xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,17150xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,17160xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,17170xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,17180xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,17190xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,17200xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,17210xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,17220xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,17230xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,17240x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,17250x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,17260x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,17270x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,17280x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,17290x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,17300x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,17310x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,17320xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,17330xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,17340xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,17350xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,17360xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,17370xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,17380xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,17390xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL1740};17411742static uint32_t1743calc_crc32(const char *p, size_t len, uint32_t crc)1744{1745uint32_t i;17461747for (i = 0; i < len; i++) {1748crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);1749}17501751return (crc ^ 0xFFFFFFFF);1752}175317541755