xref: /freebsd/contrib/elftoolchain/elfcopy/sections.c (revision 05ab65497e06edd12683163480841aa9630b9d4c)
1a85fe12eSEd Maste /*-
24a85c691SEd Maste  * Copyright (c) 2007-2011,2014 Kai Wang
3a85fe12eSEd Maste  * All rights reserved.
4a85fe12eSEd Maste  *
5a85fe12eSEd Maste  * Redistribution and use in source and binary forms, with or without
6a85fe12eSEd Maste  * modification, are permitted provided that the following conditions
7a85fe12eSEd Maste  * are met:
8a85fe12eSEd Maste  * 1. Redistributions of source code must retain the above copyright
9a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer.
10a85fe12eSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
11a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer in the
12a85fe12eSEd Maste  *    documentation and/or other materials provided with the distribution.
13a85fe12eSEd Maste  *
14a85fe12eSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a85fe12eSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a85fe12eSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a85fe12eSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a85fe12eSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a85fe12eSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a85fe12eSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a85fe12eSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a85fe12eSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a85fe12eSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a85fe12eSEd Maste  * SUCH DAMAGE.
25a85fe12eSEd Maste  */
26a85fe12eSEd Maste 
27a85fe12eSEd Maste #include <sys/param.h>
28a85fe12eSEd Maste #include <sys/stat.h>
29a85fe12eSEd Maste #include <err.h>
30a85fe12eSEd Maste #include <libgen.h>
31*05ab6549SEd Maste #include <stdbool.h>
32a85fe12eSEd Maste #include <stdio.h>
33a85fe12eSEd Maste #include <stdlib.h>
34a85fe12eSEd Maste #include <string.h>
35a85fe12eSEd Maste 
36a85fe12eSEd Maste #include "elfcopy.h"
37a85fe12eSEd Maste 
38d003e0d7SEd Maste ELFTC_VCSID("$Id: sections.c 3758 2019-06-28 01:16:50Z emaste $");
39a85fe12eSEd Maste 
40a85fe12eSEd Maste static void	add_gnu_debuglink(struct elfcopy *ecp);
41a85fe12eSEd Maste static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc);
42a85fe12eSEd Maste static void	check_section_rename(struct elfcopy *ecp, struct section *s);
43aee4c74cSEd Maste static void	filter_reloc(struct elfcopy *ecp, struct section *s);
44a85fe12eSEd Maste static int	get_section_flags(struct elfcopy *ecp, const char *name);
45a85fe12eSEd Maste static void	insert_sections(struct elfcopy *ecp);
46a85fe12eSEd Maste static int	is_append_section(struct elfcopy *ecp, const char *name);
47a85fe12eSEd Maste static int	is_compress_section(struct elfcopy *ecp, const char *name);
48a85fe12eSEd Maste static int	is_debug_section(const char *name);
4967d97fe7SEd Maste static int	is_dwo_section(const char *name);
50a85fe12eSEd Maste static int	is_modify_section(struct elfcopy *ecp, const char *name);
51a85fe12eSEd Maste static int	is_print_section(struct elfcopy *ecp, const char *name);
52a85fe12eSEd Maste static void	modify_section(struct elfcopy *ecp, struct section *s);
53a85fe12eSEd Maste static void	pad_section(struct elfcopy *ecp, struct section *s);
54a85fe12eSEd Maste static void	print_data(const char *d, size_t sz);
55a85fe12eSEd Maste static void	print_section(struct section *s);
56a85fe12eSEd Maste static void	*read_section(struct section *s, size_t *size);
57bc589b72SMark Johnston static void	set_shstrtab(struct elfcopy *ecp);
58a85fe12eSEd Maste static void	update_reloc(struct elfcopy *ecp, struct section *s);
593ef90571SEd Maste static void	update_section_group(struct elfcopy *ecp, struct section *s);
60a85fe12eSEd Maste 
61a85fe12eSEd Maste int
is_remove_section(struct elfcopy * ecp,const char * name)62a85fe12eSEd Maste is_remove_section(struct elfcopy *ecp, const char *name)
63a85fe12eSEd Maste {
64a85fe12eSEd Maste 
65a85fe12eSEd Maste 	/* Always keep section name table */
66a85fe12eSEd Maste 	if (strcmp(name, ".shstrtab") == 0)
67a85fe12eSEd Maste 		return 0;
68a85fe12eSEd Maste 	if (strcmp(name, ".symtab") == 0 ||
69a85fe12eSEd Maste 	    strcmp(name, ".strtab") == 0) {
70a85fe12eSEd Maste 		if (ecp->strip == STRIP_ALL && lookup_symop_list(
71a85fe12eSEd Maste 		    ecp, NULL, SYMOP_KEEP) == NULL)
72a85fe12eSEd Maste 			return (1);
73a85fe12eSEd Maste 		else
74a85fe12eSEd Maste 			return (0);
75a85fe12eSEd Maste 	}
76a85fe12eSEd Maste 
7767d97fe7SEd Maste 	if (ecp->strip == STRIP_DWO && is_dwo_section(name))
7867d97fe7SEd Maste 		return (1);
7967d97fe7SEd Maste 	if (ecp->strip == STRIP_NONDWO && !is_dwo_section(name))
8067d97fe7SEd Maste 		return (1);
8167d97fe7SEd Maste 
82a85fe12eSEd Maste 	if (is_debug_section(name)) {
83a85fe12eSEd Maste 		if (ecp->strip == STRIP_ALL ||
84a85fe12eSEd Maste 		    ecp->strip == STRIP_DEBUG ||
85a85fe12eSEd Maste 		    ecp->strip == STRIP_UNNEEDED ||
86a85fe12eSEd Maste 		    (ecp->flags & DISCARD_LOCAL))
87a85fe12eSEd Maste 			return (1);
88a85fe12eSEd Maste 		if (ecp->strip == STRIP_NONDEBUG)
89a85fe12eSEd Maste 			return (0);
90a85fe12eSEd Maste 	}
91a85fe12eSEd Maste 
92a85fe12eSEd Maste 	if ((ecp->flags & SEC_REMOVE) || (ecp->flags & SEC_COPY)) {
93a85fe12eSEd Maste 		struct sec_action *sac;
94a85fe12eSEd Maste 
95a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, name, 0);
96a85fe12eSEd Maste 		if ((ecp->flags & SEC_REMOVE) && sac != NULL && sac->remove)
97a85fe12eSEd Maste 			return (1);
98a85fe12eSEd Maste 		if ((ecp->flags & SEC_COPY) && (sac == NULL || !sac->copy))
99a85fe12eSEd Maste 			return (1);
100a85fe12eSEd Maste 	}
101a85fe12eSEd Maste 
102a85fe12eSEd Maste 	return (0);
103a85fe12eSEd Maste }
104a85fe12eSEd Maste 
105a85fe12eSEd Maste /*
106a85fe12eSEd Maste  * Relocation section needs to be removed if the section it applies to
107a85fe12eSEd Maste  * will be removed.
108a85fe12eSEd Maste  */
109a85fe12eSEd Maste int
is_remove_reloc_sec(struct elfcopy * ecp,uint32_t sh_info)110a85fe12eSEd Maste is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info)
111a85fe12eSEd Maste {
112a85fe12eSEd Maste 	const char	*name;
113a85fe12eSEd Maste 	GElf_Shdr	 ish;
114a85fe12eSEd Maste 	Elf_Scn		*is;
115a85fe12eSEd Maste 	size_t		 indx;
116a85fe12eSEd Maste 	int		 elferr;
117a85fe12eSEd Maste 
118a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
119a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
120a85fe12eSEd Maste 		    elf_errmsg(-1));
121a85fe12eSEd Maste 
122dc2282fcSMark Johnston 	is = elf_getscn(ecp->ein, sh_info);
123dc2282fcSMark Johnston 	if (is != NULL) {
124a85fe12eSEd Maste 		if (gelf_getshdr(is, &ish) == NULL)
125a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
126a85fe12eSEd Maste 			    elf_errmsg(-1));
127a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) ==
128a85fe12eSEd Maste 		    NULL)
129a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
130a85fe12eSEd Maste 			    elf_errmsg(-1));
131a85fe12eSEd Maste 		if (is_remove_section(ecp, name))
132a85fe12eSEd Maste 			return (1);
133a85fe12eSEd Maste 		else
134a85fe12eSEd Maste 			return (0);
135a85fe12eSEd Maste 	}
136a85fe12eSEd Maste 	elferr = elf_errno();
137a85fe12eSEd Maste 	if (elferr != 0)
138a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
139a85fe12eSEd Maste 		    elf_errmsg(elferr));
140a85fe12eSEd Maste 
141a85fe12eSEd Maste 	/* Remove reloc section if we can't find the target section. */
142a85fe12eSEd Maste 	return (1);
143a85fe12eSEd Maste }
144a85fe12eSEd Maste 
145a85fe12eSEd Maste static int
is_append_section(struct elfcopy * ecp,const char * name)146a85fe12eSEd Maste is_append_section(struct elfcopy *ecp, const char *name)
147a85fe12eSEd Maste {
148a85fe12eSEd Maste 	struct sec_action *sac;
149a85fe12eSEd Maste 
150a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
151a85fe12eSEd Maste 	if (sac != NULL && sac->append != 0 && sac->string != NULL)
152a85fe12eSEd Maste 		return (1);
153a85fe12eSEd Maste 
154a85fe12eSEd Maste 	return (0);
155a85fe12eSEd Maste }
156a85fe12eSEd Maste 
157a85fe12eSEd Maste static int
is_compress_section(struct elfcopy * ecp,const char * name)158a85fe12eSEd Maste is_compress_section(struct elfcopy *ecp, const char *name)
159a85fe12eSEd Maste {
160a85fe12eSEd Maste 	struct sec_action *sac;
161a85fe12eSEd Maste 
162a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
163a85fe12eSEd Maste 	if (sac != NULL && sac->compress != 0)
164a85fe12eSEd Maste 		return (1);
165a85fe12eSEd Maste 
166a85fe12eSEd Maste 	return (0);
167a85fe12eSEd Maste }
168a85fe12eSEd Maste 
169a85fe12eSEd Maste static void
check_section_rename(struct elfcopy * ecp,struct section * s)170a85fe12eSEd Maste check_section_rename(struct elfcopy *ecp, struct section *s)
171a85fe12eSEd Maste {
172a85fe12eSEd Maste 	struct sec_action *sac;
173a85fe12eSEd Maste 	char *prefix;
174a85fe12eSEd Maste 	size_t namelen;
175a85fe12eSEd Maste 
176a85fe12eSEd Maste 	if (s->pseudo)
177a85fe12eSEd Maste 		return;
178a85fe12eSEd Maste 
179a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, s->name, 0);
180a85fe12eSEd Maste 	if (sac != NULL && sac->rename)
181a85fe12eSEd Maste 		s->name = sac->newname;
182a85fe12eSEd Maste 
183a85fe12eSEd Maste 	if (!strcmp(s->name, ".symtab") ||
184a85fe12eSEd Maste 	    !strcmp(s->name, ".strtab") ||
185a85fe12eSEd Maste 	    !strcmp(s->name, ".shstrtab"))
186a85fe12eSEd Maste 		return;
187a85fe12eSEd Maste 
188a85fe12eSEd Maste 	prefix = NULL;
189a85fe12eSEd Maste 	if (s->loadable && ecp->prefix_alloc != NULL)
190a85fe12eSEd Maste 		prefix = ecp->prefix_alloc;
191a85fe12eSEd Maste 	else if (ecp->prefix_sec != NULL)
192a85fe12eSEd Maste 		prefix = ecp->prefix_sec;
193a85fe12eSEd Maste 
194a85fe12eSEd Maste 	if (prefix != NULL) {
195a85fe12eSEd Maste 		namelen = strlen(s->name) + strlen(prefix) + 1;
196a85fe12eSEd Maste 		if ((s->newname = malloc(namelen)) == NULL)
197a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
198a85fe12eSEd Maste 		snprintf(s->newname, namelen, "%s%s", prefix, s->name);
199a85fe12eSEd Maste 		s->name = s->newname;
200a85fe12eSEd Maste 	}
201a85fe12eSEd Maste }
202a85fe12eSEd Maste 
203a85fe12eSEd Maste static int
get_section_flags(struct elfcopy * ecp,const char * name)204a85fe12eSEd Maste get_section_flags(struct elfcopy *ecp, const char *name)
205a85fe12eSEd Maste {
206a85fe12eSEd Maste 	struct sec_action *sac;
207a85fe12eSEd Maste 
208a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
209a85fe12eSEd Maste 	if (sac != NULL && sac->flags)
210a85fe12eSEd Maste 		return sac->flags;
211a85fe12eSEd Maste 
212a85fe12eSEd Maste 	return (0);
213a85fe12eSEd Maste }
214a85fe12eSEd Maste 
215a85fe12eSEd Maste /*
216a85fe12eSEd Maste  * Determine whether the section are debugging section.
217a85fe12eSEd Maste  * According to libbfd, debugging sections are recognized
218a85fe12eSEd Maste  * only by name.
219a85fe12eSEd Maste  */
220a85fe12eSEd Maste static int
is_debug_section(const char * name)221a85fe12eSEd Maste is_debug_section(const char *name)
222a85fe12eSEd Maste {
223a85fe12eSEd Maste 	const char *dbg_sec[] = {
224839529caSEd Maste 		".apple_",
225a85fe12eSEd Maste 		".debug",
226a85fe12eSEd Maste 		".gnu.linkonce.wi.",
227a85fe12eSEd Maste 		".line",
228a85fe12eSEd Maste 		".stab",
229a85fe12eSEd Maste 		NULL
230a85fe12eSEd Maste 	};
231a85fe12eSEd Maste 	const char **p;
232a85fe12eSEd Maste 
233a85fe12eSEd Maste 	for(p = dbg_sec; *p; p++) {
234a85fe12eSEd Maste 		if (strncmp(name, *p, strlen(*p)) == 0)
235a85fe12eSEd Maste 			return (1);
236a85fe12eSEd Maste 	}
237a85fe12eSEd Maste 
238a85fe12eSEd Maste 	return (0);
239a85fe12eSEd Maste }
240a85fe12eSEd Maste 
241a85fe12eSEd Maste static int
is_dwo_section(const char * name)24267d97fe7SEd Maste is_dwo_section(const char *name)
24367d97fe7SEd Maste {
24467d97fe7SEd Maste 	size_t len;
24567d97fe7SEd Maste 
24667d97fe7SEd Maste 	if ((len = strlen(name)) > 4 && strcmp(name + len - 4, ".dwo") == 0)
24767d97fe7SEd Maste 		return (1);
24867d97fe7SEd Maste 	return (0);
24967d97fe7SEd Maste }
25067d97fe7SEd Maste 
25167d97fe7SEd Maste static int
is_print_section(struct elfcopy * ecp,const char * name)252a85fe12eSEd Maste is_print_section(struct elfcopy *ecp, const char *name)
253a85fe12eSEd Maste {
254a85fe12eSEd Maste 	struct sec_action *sac;
255a85fe12eSEd Maste 
256a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
257a85fe12eSEd Maste 	if (sac != NULL && sac->print != 0)
258a85fe12eSEd Maste 		return (1);
259a85fe12eSEd Maste 
260a85fe12eSEd Maste 	return (0);
261a85fe12eSEd Maste }
262a85fe12eSEd Maste 
263a85fe12eSEd Maste static int
is_modify_section(struct elfcopy * ecp,const char * name)264a85fe12eSEd Maste is_modify_section(struct elfcopy *ecp, const char *name)
265a85fe12eSEd Maste {
266a85fe12eSEd Maste 
267a85fe12eSEd Maste 	if (is_append_section(ecp, name) ||
268a85fe12eSEd Maste 	    is_compress_section(ecp, name))
269a85fe12eSEd Maste 		return (1);
270a85fe12eSEd Maste 
271a85fe12eSEd Maste 	return (0);
272a85fe12eSEd Maste }
273a85fe12eSEd Maste 
274a85fe12eSEd Maste struct sec_action*
lookup_sec_act(struct elfcopy * ecp,const char * name,int add)275a85fe12eSEd Maste lookup_sec_act(struct elfcopy *ecp, const char *name, int add)
276a85fe12eSEd Maste {
277a85fe12eSEd Maste 	struct sec_action *sac;
278a85fe12eSEd Maste 
279a85fe12eSEd Maste 	if (name == NULL)
280a85fe12eSEd Maste 		return NULL;
281a85fe12eSEd Maste 
282a85fe12eSEd Maste 	STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
283a85fe12eSEd Maste 		if (strcmp(name, sac->name) == 0)
284a85fe12eSEd Maste 			return sac;
285a85fe12eSEd Maste 	}
286a85fe12eSEd Maste 
287a85fe12eSEd Maste 	if (add == 0)
288a85fe12eSEd Maste 		return NULL;
289a85fe12eSEd Maste 
290a85fe12eSEd Maste 	if ((sac = malloc(sizeof(*sac))) == NULL)
291a85fe12eSEd Maste 		errx(EXIT_FAILURE, "not enough memory");
292a85fe12eSEd Maste 	memset(sac, 0, sizeof(*sac));
293a85fe12eSEd Maste 	sac->name = name;
294a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list);
295a85fe12eSEd Maste 
296a85fe12eSEd Maste 	return (sac);
297a85fe12eSEd Maste }
298a85fe12eSEd Maste 
299a85fe12eSEd Maste void
free_sec_act(struct elfcopy * ecp)300a85fe12eSEd Maste free_sec_act(struct elfcopy *ecp)
301a85fe12eSEd Maste {
302a85fe12eSEd Maste 	struct sec_action *sac, *sac_temp;
303a85fe12eSEd Maste 
304a85fe12eSEd Maste 	STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) {
305a85fe12eSEd Maste 		STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list);
306a85fe12eSEd Maste 		free(sac);
307a85fe12eSEd Maste 	}
308a85fe12eSEd Maste }
309a85fe12eSEd Maste 
310a85fe12eSEd Maste void
insert_to_sec_list(struct elfcopy * ecp,struct section * sec,int tail)311a85fe12eSEd Maste insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail)
312a85fe12eSEd Maste {
313a85fe12eSEd Maste 	struct section *s;
314a85fe12eSEd Maste 
31502816870SMark Johnston 	if (tail || TAILQ_EMPTY(&ecp->v_sec) ||
31602816870SMark Johnston 	    TAILQ_LAST(&ecp->v_sec, sectionlist)->off <= sec->off) {
31702816870SMark Johnston 		TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list);
31802816870SMark Johnston 	} else {
319a85fe12eSEd Maste 		TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
320a85fe12eSEd Maste 			if (sec->off < s->off) {
321a85fe12eSEd Maste 				TAILQ_INSERT_BEFORE(s, sec, sec_list);
32202816870SMark Johnston 				break;
323a85fe12eSEd Maste 			}
324a85fe12eSEd Maste 		}
325a85fe12eSEd Maste 	}
326a85fe12eSEd Maste 
327a85fe12eSEd Maste 	if (sec->pseudo == 0)
328a85fe12eSEd Maste 		ecp->nos++;
329a85fe12eSEd Maste }
330a85fe12eSEd Maste 
331a85fe12eSEd Maste /*
332a85fe12eSEd Maste  * First step of section creation: create scn and internal section
333a85fe12eSEd Maste  * structure, discard sections to be removed.
334a85fe12eSEd Maste  */
335a85fe12eSEd Maste void
create_scn(struct elfcopy * ecp)336a85fe12eSEd Maste create_scn(struct elfcopy *ecp)
337a85fe12eSEd Maste {
338a85fe12eSEd Maste 	struct section	*s;
339a85fe12eSEd Maste 	const char	*name;
340a85fe12eSEd Maste 	Elf_Scn		*is;
341a85fe12eSEd Maste 	GElf_Shdr	 ish;
342a85fe12eSEd Maste 	size_t		 indx;
343a85fe12eSEd Maste 	uint64_t	 oldndx, newndx;
344d938d64eSEd Maste 	int		 elferr, sec_flags, reorder;
345*05ab6549SEd Maste 	bool		 sections_added;
346a85fe12eSEd Maste 
347a85fe12eSEd Maste 	/*
348a85fe12eSEd Maste 	 * Insert a pseudo section that contains the ELF header
349a85fe12eSEd Maste 	 * and program header. Used as reference for section offset
350a85fe12eSEd Maste 	 * or load address adjustment.
351a85fe12eSEd Maste 	 */
352a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
353a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
354a85fe12eSEd Maste 	s->off = 0;
355a85fe12eSEd Maste 	s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) +
356a85fe12eSEd Maste 	    gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT);
357a85fe12eSEd Maste 	s->align = 1;
358a85fe12eSEd Maste 	s->pseudo = 1;
359a85fe12eSEd Maste 	s->loadable = add_to_inseg_list(ecp, s);
360a85fe12eSEd Maste 	insert_to_sec_list(ecp, s, 0);
361a85fe12eSEd Maste 
362a85fe12eSEd Maste 	/* Create internal .shstrtab section. */
363a85fe12eSEd Maste 	init_shstrtab(ecp);
364a85fe12eSEd Maste 
365a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
366a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
367a85fe12eSEd Maste 		    elf_errmsg(-1));
368a85fe12eSEd Maste 
369*05ab6549SEd Maste 	sections_added = false;
370d938d64eSEd Maste 	reorder = 0;
371a85fe12eSEd Maste 	is = NULL;
372a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
373a85fe12eSEd Maste 		if (gelf_getshdr(is, &ish) == NULL)
374839529caSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
375a85fe12eSEd Maste 			    elf_errmsg(-1));
376a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL)
377a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
378a85fe12eSEd Maste 			    elf_errmsg(-1));
379a85fe12eSEd Maste 
380a85fe12eSEd Maste 		/* Skip sections to be removed. */
381a85fe12eSEd Maste 		if (is_remove_section(ecp, name))
382a85fe12eSEd Maste 			continue;
383a85fe12eSEd Maste 
384a85fe12eSEd Maste 		/*
385a85fe12eSEd Maste 		 * Relocation section need to be remove if the section
386a85fe12eSEd Maste 		 * it applies will be removed.
387a85fe12eSEd Maste 		 */
388a85fe12eSEd Maste 		if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)
389a85fe12eSEd Maste 			if (ish.sh_info != 0 &&
390a85fe12eSEd Maste 			    is_remove_reloc_sec(ecp, ish.sh_info))
391a85fe12eSEd Maste 				continue;
392a85fe12eSEd Maste 
393cf781b2eSEd Maste 		/*
394cf781b2eSEd Maste 		 * Section groups should be removed if symbol table will
395cf781b2eSEd Maste 		 * be removed. (section group's signature stored in symbol
396cf781b2eSEd Maste 		 * table)
397cf781b2eSEd Maste 		 */
398cf781b2eSEd Maste 		if (ish.sh_type == SHT_GROUP && ecp->strip == STRIP_ALL)
399cf781b2eSEd Maste 			continue;
400cf781b2eSEd Maste 
401a85fe12eSEd Maste 		/* Get section flags set by user. */
402a85fe12eSEd Maste 		sec_flags = get_section_flags(ecp, name);
403a85fe12eSEd Maste 
404a85fe12eSEd Maste 		/* Create internal section object. */
405a85fe12eSEd Maste 		if (strcmp(name, ".shstrtab") != 0) {
406a85fe12eSEd Maste 			if ((s = calloc(1, sizeof(*s))) == NULL)
407a85fe12eSEd Maste 				err(EXIT_FAILURE, "calloc failed");
408a85fe12eSEd Maste 			s->name		= name;
409a85fe12eSEd Maste 			s->is		= is;
410a85fe12eSEd Maste 			s->off		= ish.sh_offset;
411a85fe12eSEd Maste 			s->sz		= ish.sh_size;
412a85fe12eSEd Maste 			s->align	= ish.sh_addralign;
413a85fe12eSEd Maste 			s->type		= ish.sh_type;
41448d41ef0SPhil Shafer 			s->flags	= ish.sh_flags;
415a85fe12eSEd Maste 			s->vma		= ish.sh_addr;
416a85fe12eSEd Maste 
417a85fe12eSEd Maste 			/*
418a85fe12eSEd Maste 			 * Search program headers to determine whether section
419a85fe12eSEd Maste 			 * is loadable, but if user explicitly set section flags
420a85fe12eSEd Maste 			 * while neither "load" nor "alloc" is set, we make the
421a85fe12eSEd Maste 			 * section unloadable.
422839529caSEd Maste 			 *
423839529caSEd Maste 			 * Sections in relocatable object is loadable if
424839529caSEd Maste 			 * section flag SHF_ALLOC is set.
425a85fe12eSEd Maste 			 */
426a85fe12eSEd Maste 			if (sec_flags &&
427a85fe12eSEd Maste 			    (sec_flags & (SF_LOAD | SF_ALLOC)) == 0)
428a85fe12eSEd Maste 				s->loadable = 0;
429839529caSEd Maste 			else {
430a85fe12eSEd Maste 				s->loadable = add_to_inseg_list(ecp, s);
431839529caSEd Maste 				if ((ecp->flags & RELOCATABLE) &&
432839529caSEd Maste 				    (ish.sh_flags & SHF_ALLOC))
433839529caSEd Maste 					s->loadable = 1;
434839529caSEd Maste 			}
435a85fe12eSEd Maste 		} else {
436a85fe12eSEd Maste 			/* Assuming .shstrtab is "unloadable". */
437a85fe12eSEd Maste 			s		= ecp->shstrtab;
438a85fe12eSEd Maste 			s->off		= ish.sh_offset;
439a85fe12eSEd Maste 		}
440a85fe12eSEd Maste 
441a85fe12eSEd Maste 		oldndx = newndx = SHN_UNDEF;
442a85fe12eSEd Maste 		if (strcmp(name, ".symtab") != 0 &&
443a85fe12eSEd Maste 		    strcmp(name, ".strtab") != 0) {
444*05ab6549SEd Maste 			/* Add new sections before .shstrtab if we have one. */
445a85fe12eSEd Maste 			if (!strcmp(name, ".shstrtab")) {
446a85fe12eSEd Maste 				/*
447a85fe12eSEd Maste 				 * Add sections specified by --add-section and
448a85fe12eSEd Maste 				 * gnu debuglink. we want these sections have
449a85fe12eSEd Maste 				 * smaller index than .shstrtab section.
450a85fe12eSEd Maste 				 */
451*05ab6549SEd Maste 				sections_added = true;
452a85fe12eSEd Maste 				if (ecp->debuglink != NULL)
453a85fe12eSEd Maste 					add_gnu_debuglink(ecp);
454a85fe12eSEd Maste 				if (ecp->flags & SEC_ADD)
455a85fe12eSEd Maste 					insert_sections(ecp);
456a85fe12eSEd Maste 			}
457a85fe12eSEd Maste  			if ((s->os = elf_newscn(ecp->eout)) == NULL)
458a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_newscn failed: %s",
459a85fe12eSEd Maste 				    elf_errmsg(-1));
460a85fe12eSEd Maste 			if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF)
461a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
462a85fe12eSEd Maste 				    elf_errmsg(-1));
463a85fe12eSEd Maste 		}
464a85fe12eSEd Maste 		if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF)
465a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
466a85fe12eSEd Maste 			    elf_errmsg(-1));
467a85fe12eSEd Maste 		if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF)
468a85fe12eSEd Maste 			ecp->secndx[oldndx] = newndx;
469a85fe12eSEd Maste 
470a85fe12eSEd Maste 		/*
471a85fe12eSEd Maste 		 * If strip action is STRIP_NONDEBUG(only keep debug),
47295fd7f26SEd Maste 		 * change sections type of loadable sections and section
47395fd7f26SEd Maste 		 * groups to SHT_NOBITS, and the content of those sections
47495fd7f26SEd Maste 		 * will be discarded. However, SHT_NOTE sections should
47595fd7f26SEd Maste 		 * be kept.
476a85fe12eSEd Maste 		 */
47795fd7f26SEd Maste 		if (ecp->strip == STRIP_NONDEBUG) {
47895fd7f26SEd Maste 			if (((ish.sh_flags & SHF_ALLOC) ||
47995fd7f26SEd Maste 			    (ish.sh_flags & SHF_GROUP)) &&
48095fd7f26SEd Maste 			    ish.sh_type != SHT_NOTE)
481a85fe12eSEd Maste 				s->type = SHT_NOBITS;
48295fd7f26SEd Maste 		}
483a85fe12eSEd Maste 
484a85fe12eSEd Maste 		check_section_rename(ecp, s);
485a85fe12eSEd Maste 
486a85fe12eSEd Maste 		/* create section header based on input object. */
487a85fe12eSEd Maste 		if (strcmp(name, ".symtab") != 0 &&
488a85fe12eSEd Maste 		    strcmp(name, ".strtab") != 0 &&
489d938d64eSEd Maste 		    strcmp(name, ".shstrtab") != 0) {
490a85fe12eSEd Maste 			copy_shdr(ecp, s, NULL, 0, sec_flags);
491d938d64eSEd Maste 			/*
492d938d64eSEd Maste 			 * elfcopy puts .symtab, .strtab and .shstrtab
493d938d64eSEd Maste 			 * sections in the end of the output object.
494d938d64eSEd Maste 			 * If the input objects have more sections
495d938d64eSEd Maste 			 * after any of these 3 sections, the section
496d938d64eSEd Maste 			 * table will be reordered. section symbols
497d938d64eSEd Maste 			 * should be regenerated for relocations.
498d938d64eSEd Maste 			 */
499d938d64eSEd Maste 			if (reorder)
500d938d64eSEd Maste 				ecp->flags &= ~SYMTAB_INTACT;
501d938d64eSEd Maste 		} else
502d938d64eSEd Maste 			reorder = 1;
503a85fe12eSEd Maste 
504a85fe12eSEd Maste 		if (strcmp(name, ".symtab") == 0) {
505a85fe12eSEd Maste 			ecp->flags |= SYMTAB_EXIST;
506a85fe12eSEd Maste 			ecp->symtab = s;
507a85fe12eSEd Maste 		}
508a85fe12eSEd Maste 		if (strcmp(name, ".strtab") == 0)
509a85fe12eSEd Maste 			ecp->strtab = s;
510a85fe12eSEd Maste 
511a85fe12eSEd Maste 		insert_to_sec_list(ecp, s, 0);
512a85fe12eSEd Maste 	}
513*05ab6549SEd Maste 	if (!sections_added) {
514*05ab6549SEd Maste 		if (ecp->debuglink != NULL)
515*05ab6549SEd Maste 			add_gnu_debuglink(ecp);
516*05ab6549SEd Maste 		if (ecp->flags & SEC_ADD)
517*05ab6549SEd Maste 			insert_sections(ecp);
518*05ab6549SEd Maste 	}
519a85fe12eSEd Maste 	elferr = elf_errno();
520a85fe12eSEd Maste 	if (elferr != 0)
521a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
522a85fe12eSEd Maste 		    elf_errmsg(elferr));
523a85fe12eSEd Maste }
524a85fe12eSEd Maste 
525a85fe12eSEd Maste struct section *
insert_shtab(struct elfcopy * ecp,int tail)526a85fe12eSEd Maste insert_shtab(struct elfcopy *ecp, int tail)
527a85fe12eSEd Maste {
528a85fe12eSEd Maste 	struct section	*s, *shtab;
529a85fe12eSEd Maste 	GElf_Ehdr	 ieh;
530a85fe12eSEd Maste 	int		 nsecs;
531a85fe12eSEd Maste 
532a85fe12eSEd Maste 	/*
533a85fe12eSEd Maste 	 * Treat section header table as a "pseudo" section, insert it
534a85fe12eSEd Maste 	 * into section list, so later it will get sorted and resynced
535a85fe12eSEd Maste 	 * just as normal sections.
536a85fe12eSEd Maste 	 */
537a85fe12eSEd Maste 	if ((shtab = calloc(1, sizeof(*shtab))) == NULL)
538a85fe12eSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
539a85fe12eSEd Maste 	if (!tail) {
5404a85c691SEd Maste 		/*
5414a85c691SEd Maste 		 * "shoff" of input object is used as a hint for section
5424a85c691SEd Maste 		 * resync later.
5434a85c691SEd Maste 		 */
544a85fe12eSEd Maste 		if (gelf_getehdr(ecp->ein, &ieh) == NULL)
545a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
546a85fe12eSEd Maste 			    elf_errmsg(-1));
547a85fe12eSEd Maste 		shtab->off = ieh.e_shoff;
548a85fe12eSEd Maste 	} else
549a85fe12eSEd Maste 		shtab->off = 0;
550a85fe12eSEd Maste 	/* Calculate number of sections in the output object. */
551a85fe12eSEd Maste 	nsecs = 0;
552a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
553a85fe12eSEd Maste 		if (!s->pseudo)
554a85fe12eSEd Maste 			nsecs++;
555a85fe12eSEd Maste 	}
556a85fe12eSEd Maste 	/* Remember there is always a null section, so we +1 here. */
557a85fe12eSEd Maste 	shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT);
558a85fe12eSEd Maste 	if (shtab->sz == 0)
559a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
560a85fe12eSEd Maste 	shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8);
561a85fe12eSEd Maste 	shtab->loadable = 0;
562a85fe12eSEd Maste 	shtab->pseudo = 1;
563a85fe12eSEd Maste 	insert_to_sec_list(ecp, shtab, tail);
564a85fe12eSEd Maste 
565a85fe12eSEd Maste 	return (shtab);
566a85fe12eSEd Maste }
567a85fe12eSEd Maste 
568a85fe12eSEd Maste void
copy_content(struct elfcopy * ecp)569a85fe12eSEd Maste copy_content(struct elfcopy *ecp)
570a85fe12eSEd Maste {
571a85fe12eSEd Maste 	struct section *s;
572a85fe12eSEd Maste 
573a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
574a85fe12eSEd Maste 		/* Skip pseudo section. */
575a85fe12eSEd Maste 		if (s->pseudo)
576a85fe12eSEd Maste 			continue;
577a85fe12eSEd Maste 
578a85fe12eSEd Maste 		/* Skip special sections. */
579a85fe12eSEd Maste 		if (strcmp(s->name, ".symtab") == 0 ||
580a85fe12eSEd Maste 		    strcmp(s->name, ".strtab") == 0 ||
581a85fe12eSEd Maste 		    strcmp(s->name, ".shstrtab") == 0)
582a85fe12eSEd Maste 			continue;
583a85fe12eSEd Maste 
584a85fe12eSEd Maste 		/*
585aee4c74cSEd Maste 		 * If strip action is STRIP_ALL, relocation info need
586aee4c74cSEd Maste 		 * to be stripped. Skip filtering otherwisw.
587aee4c74cSEd Maste 		 */
588aee4c74cSEd Maste 		if (ecp->strip == STRIP_ALL &&
589aee4c74cSEd Maste 		    (s->type == SHT_REL || s->type == SHT_RELA))
590aee4c74cSEd Maste 			filter_reloc(ecp, s);
591aee4c74cSEd Maste 
592aee4c74cSEd Maste 		/*
5933ef90571SEd Maste 		 * The section indices in the SHT_GROUP section needs
5943ef90571SEd Maste 		 * to be updated since we might have stripped some
5953ef90571SEd Maste 		 * sections and changed section numbering.
5963ef90571SEd Maste 		 */
5973ef90571SEd Maste 		if (s->type == SHT_GROUP)
5983ef90571SEd Maste 			update_section_group(ecp, s);
5993ef90571SEd Maste 
600a85fe12eSEd Maste 		if (is_modify_section(ecp, s->name))
601a85fe12eSEd Maste 			modify_section(ecp, s);
602a85fe12eSEd Maste 
603a85fe12eSEd Maste 		copy_data(s);
604a85fe12eSEd Maste 
605a85fe12eSEd Maste 		/*
606a85fe12eSEd Maste 		 * If symbol table is modified, relocation info might
607a85fe12eSEd Maste 		 * need update, as symbol index may have changed.
608a85fe12eSEd Maste 		 */
609a85fe12eSEd Maste 		if ((ecp->flags & SYMTAB_INTACT) == 0 &&
610a85fe12eSEd Maste 		    (ecp->flags & SYMTAB_EXIST) &&
611a85fe12eSEd Maste 		    (s->type == SHT_REL || s->type == SHT_RELA))
612a85fe12eSEd Maste 			update_reloc(ecp, s);
613a85fe12eSEd Maste 
614a85fe12eSEd Maste 		if (is_print_section(ecp, s->name))
615a85fe12eSEd Maste 			print_section(s);
616a85fe12eSEd Maste 	}
617a85fe12eSEd Maste }
618a85fe12eSEd Maste 
6193ef90571SEd Maste 
6203ef90571SEd Maste /*
6213ef90571SEd Maste  * Update section group section. The section indices in the SHT_GROUP
6223ef90571SEd Maste  * section need update after section numbering changed.
6233ef90571SEd Maste  */
6243ef90571SEd Maste static void
update_section_group(struct elfcopy * ecp,struct section * s)6253ef90571SEd Maste update_section_group(struct elfcopy *ecp, struct section *s)
6263ef90571SEd Maste {
6273ef90571SEd Maste 	GElf_Shdr	 ish;
6283ef90571SEd Maste 	Elf_Data	*id;
6293ef90571SEd Maste 	uint32_t	*ws, *wd;
6303ef90571SEd Maste 	uint64_t	 n;
6313ef90571SEd Maste 	size_t		 ishnum;
6323ef90571SEd Maste 	int		 i, j;
6333ef90571SEd Maste 
6343ef90571SEd Maste 	if (!elf_getshnum(ecp->ein, &ishnum))
6353ef90571SEd Maste 		errx(EXIT_FAILURE, "elf_getshnum failed: %s",
6363ef90571SEd Maste 		    elf_errmsg(-1));
6373ef90571SEd Maste 
6383ef90571SEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
6393ef90571SEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
6403ef90571SEd Maste 		    elf_errmsg(-1));
6413ef90571SEd Maste 
6423ef90571SEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL)
6433ef90571SEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
6443ef90571SEd Maste 		    elf_errmsg(-1));
6453ef90571SEd Maste 
6463ef90571SEd Maste 	if (ish.sh_size == 0)
6473ef90571SEd Maste 		return;
6483ef90571SEd Maste 
6493ef90571SEd Maste 	if (ish.sh_entsize == 0)
6503ef90571SEd Maste 		ish.sh_entsize = 4;
6513ef90571SEd Maste 
6523ef90571SEd Maste 	ws = id->d_buf;
6533ef90571SEd Maste 
6543ef90571SEd Maste 	/* We only support COMDAT section. */
6553ef90571SEd Maste #ifndef GRP_COMDAT
6563ef90571SEd Maste #define	GRP_COMDAT 0x1
6573ef90571SEd Maste #endif
6583ef90571SEd Maste 	if ((*ws & GRP_COMDAT) == 0)
6593ef90571SEd Maste 		return;
6603ef90571SEd Maste 
6613ef90571SEd Maste 	if ((s->buf = malloc(ish.sh_size)) == NULL)
6623ef90571SEd Maste 		err(EXIT_FAILURE, "malloc failed");
6633ef90571SEd Maste 
6643ef90571SEd Maste 	s->sz = ish.sh_size;
6653ef90571SEd Maste 
6663ef90571SEd Maste 	wd = s->buf;
6673ef90571SEd Maste 
6683ef90571SEd Maste 	/* Copy the flag word as-is. */
6693ef90571SEd Maste 	*wd = *ws;
6703ef90571SEd Maste 
6713ef90571SEd Maste 	/* Update the section indices. */
6723ef90571SEd Maste 	n = ish.sh_size / ish.sh_entsize;
6733ef90571SEd Maste 	for(i = 1, j = 1; (uint64_t)i < n; i++) {
6743ef90571SEd Maste 		if (ws[i] != SHN_UNDEF && ws[i] < ishnum &&
6753ef90571SEd Maste 		    ecp->secndx[ws[i]] != 0)
6763ef90571SEd Maste 			wd[j++] = ecp->secndx[ws[i]];
6773ef90571SEd Maste 		else
6783ef90571SEd Maste 			s->sz -= 4;
6793ef90571SEd Maste 	}
6803ef90571SEd Maste 
6813ef90571SEd Maste 	s->nocopy = 1;
6823ef90571SEd Maste }
6833ef90571SEd Maste 
684aee4c74cSEd Maste /*
685aee4c74cSEd Maste  * Filter relocation entries, only keep those entries whose
686aee4c74cSEd Maste  * symbol is in the keep list.
687aee4c74cSEd Maste  */
688aee4c74cSEd Maste static void
filter_reloc(struct elfcopy * ecp,struct section * s)689aee4c74cSEd Maste filter_reloc(struct elfcopy *ecp, struct section *s)
690aee4c74cSEd Maste {
691aee4c74cSEd Maste 	const char	*name;
692aee4c74cSEd Maste 	GElf_Shdr	 ish;
693aee4c74cSEd Maste 	GElf_Rel	 rel;
694aee4c74cSEd Maste 	GElf_Rela	 rela;
695aee4c74cSEd Maste 	Elf32_Rel	*rel32;
696aee4c74cSEd Maste 	Elf64_Rel	*rel64;
697aee4c74cSEd Maste 	Elf32_Rela	*rela32;
698aee4c74cSEd Maste 	Elf64_Rela	*rela64;
699aee4c74cSEd Maste 	Elf_Data	*id;
700aee4c74cSEd Maste 	uint64_t	 cap, n, nrels, sym;
701aee4c74cSEd Maste 	int		 elferr, i;
702aee4c74cSEd Maste 
703aee4c74cSEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
704aee4c74cSEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
705aee4c74cSEd Maste 		    elf_errmsg(-1));
706aee4c74cSEd Maste 
707aee4c74cSEd Maste 	/* We don't want to touch relocation info for dynamic symbols. */
708aee4c74cSEd Maste 	if ((ecp->flags & SYMTAB_EXIST) == 0) {
709aee4c74cSEd Maste 		/*
710aee4c74cSEd Maste 		 * No symbol table in output.  If sh_link points to a section
711aee4c74cSEd Maste 		 * that exists in the output object, this relocation section
712aee4c74cSEd Maste 		 * is for dynamic symbols.  Don't touch it.
713aee4c74cSEd Maste 		 */
714aee4c74cSEd Maste 		if (ish.sh_link != 0 && ecp->secndx[ish.sh_link] != 0)
715aee4c74cSEd Maste 			return;
716aee4c74cSEd Maste 	} else {
717aee4c74cSEd Maste 		/* Symbol table exist, check if index equals. */
718aee4c74cSEd Maste 		if (ish.sh_link != elf_ndxscn(ecp->symtab->is))
719aee4c74cSEd Maste 			return;
720aee4c74cSEd Maste 	}
721aee4c74cSEd Maste 
722aee4c74cSEd Maste #define	COPYREL(REL, SZ) do {					\
723aee4c74cSEd Maste 	if (nrels == 0) {					\
724aee4c74cSEd Maste 		if ((REL##SZ = malloc(cap *			\
725aee4c74cSEd Maste 		    sizeof(*REL##SZ))) == NULL)			\
726aee4c74cSEd Maste 			err(EXIT_FAILURE, "malloc failed");	\
727aee4c74cSEd Maste 	}							\
728aee4c74cSEd Maste 	if (nrels >= cap) {					\
729aee4c74cSEd Maste 		cap *= 2;					\
730aee4c74cSEd Maste 		if ((REL##SZ = realloc(REL##SZ, cap *		\
731aee4c74cSEd Maste 		    sizeof(*REL##SZ))) == NULL)			\
732aee4c74cSEd Maste 			err(EXIT_FAILURE, "realloc failed");	\
733aee4c74cSEd Maste 	}							\
734aee4c74cSEd Maste 	REL##SZ[nrels].r_offset = REL.r_offset;			\
735aee4c74cSEd Maste 	REL##SZ[nrels].r_info	= REL.r_info;			\
736aee4c74cSEd Maste 	if (s->type == SHT_RELA)				\
737aee4c74cSEd Maste 		rela##SZ[nrels].r_addend = rela.r_addend;	\
738aee4c74cSEd Maste 	nrels++;						\
739aee4c74cSEd Maste } while (0)
740aee4c74cSEd Maste 
741aee4c74cSEd Maste 	nrels = 0;
742aee4c74cSEd Maste 	cap = 4;		/* keep list is usually small. */
743aee4c74cSEd Maste 	rel32 = NULL;
744aee4c74cSEd Maste 	rel64 = NULL;
745aee4c74cSEd Maste 	rela32 = NULL;
746aee4c74cSEd Maste 	rela64 = NULL;
747aee4c74cSEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL)
748aee4c74cSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
749aee4c74cSEd Maste 		    elf_errmsg(-1));
750aee4c74cSEd Maste 	n = ish.sh_size / ish.sh_entsize;
751aee4c74cSEd Maste 	for(i = 0; (uint64_t)i < n; i++) {
752aee4c74cSEd Maste 		if (s->type == SHT_REL) {
753aee4c74cSEd Maste 			if (gelf_getrel(id, i, &rel) != &rel)
754aee4c74cSEd Maste 				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
755aee4c74cSEd Maste 				    elf_errmsg(-1));
756aee4c74cSEd Maste 			sym = GELF_R_SYM(rel.r_info);
757aee4c74cSEd Maste 		} else {
758aee4c74cSEd Maste 			if (gelf_getrela(id, i, &rela) != &rela)
759aee4c74cSEd Maste 				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
760aee4c74cSEd Maste 				    elf_errmsg(-1));
761aee4c74cSEd Maste 			sym = GELF_R_SYM(rela.r_info);
762aee4c74cSEd Maste 		}
763aee4c74cSEd Maste 		/*
764aee4c74cSEd Maste 		 * If a relocation references a symbol and we are omitting
765aee4c74cSEd Maste 		 * either that symbol or the entire symbol table we cannot
766aee4c74cSEd Maste 		 * produce valid output, and so just omit the relocation.
767aee4c74cSEd Maste 		 * Broken output like this is generally not useful, but some
768aee4c74cSEd Maste 		 * uses of elfcopy/strip rely on it - for example, GCC's build
769aee4c74cSEd Maste 		 * process uses it to check for build reproducibility by
770aee4c74cSEd Maste 		 * stripping objects and comparing them.
771aee4c74cSEd Maste 		 *
772aee4c74cSEd Maste 		 * Relocations that do not reference a symbol are retained.
773aee4c74cSEd Maste 		 */
774aee4c74cSEd Maste 		if (sym != 0) {
775aee4c74cSEd Maste 			if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0)
776aee4c74cSEd Maste 				continue;
777aee4c74cSEd Maste 			name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is),
778aee4c74cSEd Maste 			    sym);
779aee4c74cSEd Maste 			if (name == NULL)
780aee4c74cSEd Maste 				errx(EXIT_FAILURE, "elf_strptr failed: %s",
781aee4c74cSEd Maste 				    elf_errmsg(-1));
782aee4c74cSEd Maste 			if (lookup_symop_list(ecp, name, SYMOP_KEEP) == NULL)
783aee4c74cSEd Maste 				continue;
784aee4c74cSEd Maste 		}
785aee4c74cSEd Maste 		if (ecp->oec == ELFCLASS32) {
786aee4c74cSEd Maste 			if (s->type == SHT_REL)
787aee4c74cSEd Maste 				COPYREL(rel, 32);
788aee4c74cSEd Maste 			else
789aee4c74cSEd Maste 				COPYREL(rela, 32);
790aee4c74cSEd Maste 		} else {
791aee4c74cSEd Maste 			if (s->type == SHT_REL)
792aee4c74cSEd Maste 				COPYREL(rel, 64);
793aee4c74cSEd Maste 			else
794aee4c74cSEd Maste 				COPYREL(rela, 64);
795aee4c74cSEd Maste 		}
796aee4c74cSEd Maste 	}
797aee4c74cSEd Maste 	elferr = elf_errno();
798aee4c74cSEd Maste 	if (elferr != 0)
799aee4c74cSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
800aee4c74cSEd Maste 		    elf_errmsg(elferr));
801aee4c74cSEd Maste 
802aee4c74cSEd Maste 	if (ecp->oec == ELFCLASS32) {
803aee4c74cSEd Maste 		if (s->type == SHT_REL)
804aee4c74cSEd Maste 			s->buf = rel32;
805aee4c74cSEd Maste 		else
806aee4c74cSEd Maste 			s->buf = rela32;
807aee4c74cSEd Maste 	} else {
808aee4c74cSEd Maste 		if (s->type == SHT_REL)
809aee4c74cSEd Maste 			s->buf = rel64;
810aee4c74cSEd Maste 		else
811aee4c74cSEd Maste 			s->buf = rela64;
812aee4c74cSEd Maste 	}
813aee4c74cSEd Maste 	s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL :
814aee4c74cSEd Maste 	    ELF_T_RELA), nrels, EV_CURRENT);
815aee4c74cSEd Maste 	s->nocopy = 1;
816aee4c74cSEd Maste }
817aee4c74cSEd Maste 
818a85fe12eSEd Maste static void
update_reloc(struct elfcopy * ecp,struct section * s)819a85fe12eSEd Maste update_reloc(struct elfcopy *ecp, struct section *s)
820a85fe12eSEd Maste {
821a85fe12eSEd Maste 	GElf_Shdr	 osh;
822a85fe12eSEd Maste 	GElf_Rel	 rel;
823a85fe12eSEd Maste 	GElf_Rela	 rela;
824a85fe12eSEd Maste 	Elf_Data	*od;
825a85fe12eSEd Maste 	uint64_t	 n;
826a85fe12eSEd Maste 	int		 i;
827a85fe12eSEd Maste 
828a85fe12eSEd Maste #define UPDATEREL(REL) do {						\
829a85fe12eSEd Maste 	if (gelf_get##REL(od, i, &REL) != &REL)				\
830a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_get##REL failed: %s",		\
831a85fe12eSEd Maste 		    elf_errmsg(-1));					\
832a85fe12eSEd Maste 	REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)],	\
833a85fe12eSEd Maste 	    GELF_R_TYPE(REL.r_info));					\
834a85fe12eSEd Maste 	if (!gelf_update_##REL(od, i, &REL))				\
835a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_##REL failed: %s",	\
836a85fe12eSEd Maste 		    elf_errmsg(-1));					\
837a85fe12eSEd Maste } while(0)
838a85fe12eSEd Maste 
839a85fe12eSEd Maste 	if (s->sz == 0)
840a85fe12eSEd Maste 		return;
841a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
842a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
843a85fe12eSEd Maste 		    elf_errmsg(-1));
844a85fe12eSEd Maste 	/* Only process .symtab reloc info. */
845a85fe12eSEd Maste 	if (osh.sh_link != elf_ndxscn(ecp->symtab->is))
846a85fe12eSEd Maste 		return;
847a85fe12eSEd Maste 	if ((od = elf_getdata(s->os, NULL)) == NULL)
848a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
849a85fe12eSEd Maste 		    elf_errmsg(-1));
850a85fe12eSEd Maste 	n = osh.sh_size / osh.sh_entsize;
851a85fe12eSEd Maste 	for(i = 0; (uint64_t)i < n; i++) {
852a85fe12eSEd Maste 		if (s->type == SHT_REL)
853a85fe12eSEd Maste 			UPDATEREL(rel);
854a85fe12eSEd Maste 		else
855a85fe12eSEd Maste 			UPDATEREL(rela);
856a85fe12eSEd Maste 	}
857a85fe12eSEd Maste }
858a85fe12eSEd Maste 
859a85fe12eSEd Maste static void
pad_section(struct elfcopy * ecp,struct section * s)860a85fe12eSEd Maste pad_section(struct elfcopy *ecp, struct section *s)
861a85fe12eSEd Maste {
862a85fe12eSEd Maste 	GElf_Shdr	 osh;
863a85fe12eSEd Maste 	Elf_Data	*od;
864a85fe12eSEd Maste 
865a85fe12eSEd Maste 	if (s == NULL || s->pad_sz == 0)
866a85fe12eSEd Maste 		return;
867a85fe12eSEd Maste 
868a85fe12eSEd Maste 	if ((s->pad = malloc(s->pad_sz)) == NULL)
869a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
870a85fe12eSEd Maste 	memset(s->pad, ecp->fill, s->pad_sz);
871a85fe12eSEd Maste 
872a85fe12eSEd Maste 	/* Create a new Elf_Data to contain the padding bytes. */
873a85fe12eSEd Maste 	if ((od = elf_newdata(s->os)) == NULL)
874a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
875a85fe12eSEd Maste 		    elf_errmsg(-1));
876a85fe12eSEd Maste 	od->d_align = 1;
877a85fe12eSEd Maste 	od->d_off = s->sz;
878a85fe12eSEd Maste 	od->d_buf = s->pad;
879a85fe12eSEd Maste 	od->d_type = ELF_T_BYTE;
880a85fe12eSEd Maste 	od->d_size = s->pad_sz;
881a85fe12eSEd Maste 	od->d_version = EV_CURRENT;
882a85fe12eSEd Maste 
883a85fe12eSEd Maste 	/* Update section header. */
884a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
885a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
886a85fe12eSEd Maste 		    elf_errmsg(-1));
887a85fe12eSEd Maste 	osh.sh_size = s->sz + s->pad_sz;
888a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &osh))
889a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
890a85fe12eSEd Maste 		    elf_errmsg(-1));
891a85fe12eSEd Maste }
892a85fe12eSEd Maste 
8934133f236SEd Maste static int
section_type_alignment(int sht,int class)8944133f236SEd Maste section_type_alignment(int sht, int class)
8954133f236SEd Maste {
8964133f236SEd Maste 	switch (sht)
8974133f236SEd Maste 	{
8984133f236SEd Maste 	case SHT_DYNAMIC:
8994133f236SEd Maste 	case SHT_DYNSYM:
9004133f236SEd Maste 	case SHT_FINI_ARRAY:
9014133f236SEd Maste 	case SHT_GNU_HASH:
9024133f236SEd Maste 	case SHT_INIT_ARRAY:
9034133f236SEd Maste 	case SHT_PREINIT_ARRAY:
9044133f236SEd Maste 	case SHT_REL:
9054133f236SEd Maste 	case SHT_RELA:
9064133f236SEd Maste 	case SHT_SYMTAB:
9074133f236SEd Maste 		return (class == ELFCLASS64 ? 8 : 4);
9084133f236SEd Maste 	case SHT_SUNW_move:
9094133f236SEd Maste 		return (8);
9104133f236SEd Maste 	case SHT_GNU_LIBLIST:
9114133f236SEd Maste 	case SHT_GROUP:
9124133f236SEd Maste 	case SHT_HASH:
9134133f236SEd Maste 	case SHT_NOTE:
9144133f236SEd Maste 	case SHT_SUNW_verdef:	/* == SHT_GNU_verdef */
9154133f236SEd Maste 	case SHT_SUNW_verneed:	/* == SHT_GNU_verneed */
9164133f236SEd Maste 	case SHT_SYMTAB_SHNDX:
9174133f236SEd Maste 		return (4);
9184133f236SEd Maste 	case SHT_SUNW_syminfo:
9194133f236SEd Maste 	case SHT_SUNW_versym:	/* == SHT_GNU_versym */
9204133f236SEd Maste 		return (2);
9214133f236SEd Maste 	case SHT_NOBITS:
9224133f236SEd Maste 	case SHT_PROGBITS:
9234133f236SEd Maste 	case SHT_STRTAB:
9244133f236SEd Maste 	case SHT_SUNW_dof:
9254133f236SEd Maste 		return (1);
9264133f236SEd Maste 	}
9274133f236SEd Maste 	return (1);
9284133f236SEd Maste }
9294133f236SEd Maste 
930a85fe12eSEd Maste void
resync_sections(struct elfcopy * ecp)931a85fe12eSEd Maste resync_sections(struct elfcopy *ecp)
932a85fe12eSEd Maste {
933a85fe12eSEd Maste 	struct section	*s, *ps;
934a85fe12eSEd Maste 	GElf_Shdr	 osh;
935a85fe12eSEd Maste 	uint64_t	 off;
936a85fe12eSEd Maste 	int		 first;
9374133f236SEd Maste 	int		 min_alignment;
938a85fe12eSEd Maste 
939a85fe12eSEd Maste 	ps = NULL;
940a85fe12eSEd Maste 	first = 1;
941a85fe12eSEd Maste 	off = 0;
942a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
943a85fe12eSEd Maste 		if (first) {
944a85fe12eSEd Maste 			off = s->off;
945a85fe12eSEd Maste 			first = 0;
946a85fe12eSEd Maste 		}
947a85fe12eSEd Maste 
9484a85c691SEd Maste 		/*
9494a85c691SEd Maste 		 * Ignore TLS sections with load address 0 and without
9504a85c691SEd Maste 		 * content. We don't need to adjust their file offset or
9514a85c691SEd Maste 		 * VMA, only the size matters.
9524a85c691SEd Maste 		 */
9534a85c691SEd Maste 		if (s->seg_tls != NULL && s->type == SHT_NOBITS &&
9544a85c691SEd Maste 		    s->off == 0)
9554a85c691SEd Maste 			continue;
9564a85c691SEd Maste 
957a85fe12eSEd Maste 		/* Align section offset. */
9582b39d4f6SEd Maste 		if (s->align == 0)
9592b39d4f6SEd Maste 			s->align = 1;
9604133f236SEd Maste 		min_alignment = section_type_alignment(s->type, ecp->oec);
9614133f236SEd Maste 		if (s->align < INT_MAX && (int)s->align < min_alignment) {
9624133f236SEd Maste 			warnx("section %s alignment %d increased to %d",
9634133f236SEd Maste 			    s->name, (int)s->align, min_alignment);
9644133f236SEd Maste 			s->align = min_alignment;
9654133f236SEd Maste 		}
966a85fe12eSEd Maste 		if (off <= s->off) {
967839529caSEd Maste 			if (!s->loadable || (ecp->flags & RELOCATABLE))
968a85fe12eSEd Maste 				s->off = roundup(off, s->align);
969a85fe12eSEd Maste 		} else {
970839529caSEd Maste 			if (s->loadable && (ecp->flags & RELOCATABLE) == 0)
97117eee522SEd Maste 				warnx("moving loadable section %s, "
97217eee522SEd Maste 				    "is this intentional?", s->name);
973a85fe12eSEd Maste 			s->off = roundup(off, s->align);
974a85fe12eSEd Maste 		}
975a85fe12eSEd Maste 
976a85fe12eSEd Maste 		/* Calculate next section offset. */
977a85fe12eSEd Maste 		off = s->off;
978a85fe12eSEd Maste 		if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL))
979a85fe12eSEd Maste 			off += s->sz;
980a85fe12eSEd Maste 
981a85fe12eSEd Maste 		if (s->pseudo) {
982a85fe12eSEd Maste 			ps = NULL;
983a85fe12eSEd Maste 			continue;
984a85fe12eSEd Maste 		}
985a85fe12eSEd Maste 
986a85fe12eSEd Maste 		/* Count padding bytes added through --pad-to. */
987a85fe12eSEd Maste 		if (s->pad_sz > 0)
988a85fe12eSEd Maste 			off += s->pad_sz;
989a85fe12eSEd Maste 
990a85fe12eSEd Maste 		/* Update section header accordingly. */
991a85fe12eSEd Maste 		if (gelf_getshdr(s->os, &osh) == NULL)
992a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
993a85fe12eSEd Maste 			    elf_errmsg(-1));
994a85fe12eSEd Maste 		osh.sh_addr = s->vma;
9954133f236SEd Maste 		osh.sh_addralign = s->align;
996a85fe12eSEd Maste 		osh.sh_offset = s->off;
997a85fe12eSEd Maste 		osh.sh_size = s->sz;
998a85fe12eSEd Maste 		if (!gelf_update_shdr(s->os, &osh))
999a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
1000a85fe12eSEd Maste 			    elf_errmsg(-1));
1001a85fe12eSEd Maste 
1002a85fe12eSEd Maste 		/* Add padding for previous section, if need. */
1003a85fe12eSEd Maste 		if (ps != NULL) {
1004a85fe12eSEd Maste 			if (ps->pad_sz > 0) {
1005a85fe12eSEd Maste 				/* Apply padding added by --pad-to. */
1006a85fe12eSEd Maste 				pad_section(ecp, ps);
1007a85fe12eSEd Maste 			} else if ((ecp->flags & GAP_FILL) &&
1008a85fe12eSEd Maste 			    (ps->off + ps->sz < s->off)) {
1009a85fe12eSEd Maste 				/*
1010a85fe12eSEd Maste 				 * Fill the gap between sections by padding
1011a85fe12eSEd Maste 				 * the section with lower address.
1012a85fe12eSEd Maste 				 */
1013a85fe12eSEd Maste 				ps->pad_sz = s->off - (ps->off + ps->sz);
1014a85fe12eSEd Maste 				pad_section(ecp, ps);
1015a85fe12eSEd Maste 			}
1016a85fe12eSEd Maste 		}
1017a85fe12eSEd Maste 
1018a85fe12eSEd Maste 		ps = s;
1019a85fe12eSEd Maste 	}
1020a85fe12eSEd Maste 
1021a85fe12eSEd Maste 	/* Pad the last section, if need. */
1022a85fe12eSEd Maste 	if (ps != NULL && ps->pad_sz > 0)
1023a85fe12eSEd Maste 		pad_section(ecp, ps);
1024a85fe12eSEd Maste }
1025a85fe12eSEd Maste 
1026a85fe12eSEd Maste static void
modify_section(struct elfcopy * ecp,struct section * s)1027a85fe12eSEd Maste modify_section(struct elfcopy *ecp, struct section *s)
1028a85fe12eSEd Maste {
1029a85fe12eSEd Maste 	struct sec_action	*sac;
1030a85fe12eSEd Maste 	size_t			 srcsz, dstsz, p, len;
1031a85fe12eSEd Maste 	char			*b, *c, *d, *src, *end;
1032a85fe12eSEd Maste 	int			 dupe;
1033a85fe12eSEd Maste 
1034a85fe12eSEd Maste 	src = read_section(s, &srcsz);
1035a85fe12eSEd Maste 	if (src == NULL || srcsz == 0) {
1036a85fe12eSEd Maste 		/* For empty section, we proceed if we need to append. */
1037a85fe12eSEd Maste 		if (!is_append_section(ecp, s->name))
1038a85fe12eSEd Maste 			return;
1039a85fe12eSEd Maste 	}
1040a85fe12eSEd Maste 
1041a85fe12eSEd Maste 	/* Allocate buffer needed for new section data. */
1042a85fe12eSEd Maste 	dstsz = srcsz;
1043a85fe12eSEd Maste 	if (is_append_section(ecp, s->name)) {
1044a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
1045a85fe12eSEd Maste 		dstsz += strlen(sac->string) + 1;
1046a85fe12eSEd Maste 	}
1047a85fe12eSEd Maste 	if ((b = malloc(dstsz)) == NULL)
1048a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1049a85fe12eSEd Maste 	s->buf = b;
1050a85fe12eSEd Maste 
1051a85fe12eSEd Maste 	/* Compress section. */
1052a85fe12eSEd Maste 	p = 0;
1053a85fe12eSEd Maste 	if (is_compress_section(ecp, s->name)) {
1054a85fe12eSEd Maste 		end = src + srcsz;
1055a85fe12eSEd Maste 		for(c = src; c < end;) {
1056a85fe12eSEd Maste 			len = 0;
1057a85fe12eSEd Maste 			while(c + len < end && c[len] != '\0')
1058a85fe12eSEd Maste 				len++;
1059a85fe12eSEd Maste 			if (c + len == end) {
1060a85fe12eSEd Maste 				/* XXX should we warn here? */
1061a85fe12eSEd Maste 				strncpy(&b[p], c, len);
1062a85fe12eSEd Maste 				p += len;
1063a85fe12eSEd Maste 				break;
1064a85fe12eSEd Maste 			}
1065a85fe12eSEd Maste 			dupe = 0;
1066a85fe12eSEd Maste 			for (d = b; d < b + p; ) {
1067a85fe12eSEd Maste 				if (strcmp(d, c) == 0) {
1068a85fe12eSEd Maste 					dupe = 1;
1069a85fe12eSEd Maste 					break;
1070a85fe12eSEd Maste 				}
1071a85fe12eSEd Maste 				d += strlen(d) + 1;
1072a85fe12eSEd Maste 			}
1073a85fe12eSEd Maste 			if (!dupe) {
1074a85fe12eSEd Maste 				strncpy(&b[p], c, len);
1075a85fe12eSEd Maste 				b[p + len] = '\0';
1076a85fe12eSEd Maste 				p += len + 1;
1077a85fe12eSEd Maste 			}
1078a85fe12eSEd Maste 			c += len + 1;
1079a85fe12eSEd Maste 		}
1080a85fe12eSEd Maste 	} else {
1081a85fe12eSEd Maste 		memcpy(b, src, srcsz);
1082a85fe12eSEd Maste 		p += srcsz;
1083a85fe12eSEd Maste 	}
1084a85fe12eSEd Maste 
1085a85fe12eSEd Maste 	/* Append section. */
1086a85fe12eSEd Maste 	if (is_append_section(ecp, s->name)) {
1087a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
1088a85fe12eSEd Maste 		len = strlen(sac->string);
1089a85fe12eSEd Maste 		strncpy(&b[p], sac->string, len);
1090a85fe12eSEd Maste 		b[p + len] = '\0';
1091a85fe12eSEd Maste 		p += len + 1;
1092a85fe12eSEd Maste 	}
1093a85fe12eSEd Maste 
1094a85fe12eSEd Maste 	s->sz = p;
1095a85fe12eSEd Maste 	s->nocopy = 1;
1096a85fe12eSEd Maste }
1097a85fe12eSEd Maste 
1098a85fe12eSEd Maste static void
print_data(const char * d,size_t sz)1099a85fe12eSEd Maste print_data(const char *d, size_t sz)
1100a85fe12eSEd Maste {
1101a85fe12eSEd Maste 	const char *c;
1102a85fe12eSEd Maste 
1103a85fe12eSEd Maste 	for (c = d; c < d + sz; c++) {
1104a85fe12eSEd Maste 		if (*c == '\0')
1105a85fe12eSEd Maste 			putchar('\n');
1106a85fe12eSEd Maste 		else
1107a85fe12eSEd Maste 			putchar(*c);
1108a85fe12eSEd Maste 	}
1109a85fe12eSEd Maste }
1110a85fe12eSEd Maste 
1111a85fe12eSEd Maste static void
print_section(struct section * s)1112a85fe12eSEd Maste print_section(struct section *s)
1113a85fe12eSEd Maste {
1114a85fe12eSEd Maste 	Elf_Data	*id;
1115a85fe12eSEd Maste 	int		 elferr;
1116a85fe12eSEd Maste 
1117a85fe12eSEd Maste 	if (s->buf != NULL && s->sz > 0) {
1118a85fe12eSEd Maste 		print_data(s->buf, s->sz);
1119a85fe12eSEd Maste 	} else {
1120a85fe12eSEd Maste 		id = NULL;
1121839529caSEd Maste 		while ((id = elf_getdata(s->is, id)) != NULL ||
1122839529caSEd Maste 		    (id = elf_rawdata(s->is, id)) != NULL) {
1123839529caSEd Maste 			(void) elf_errno();
1124a85fe12eSEd Maste 			print_data(id->d_buf, id->d_size);
1125839529caSEd Maste 		}
1126a85fe12eSEd Maste 		elferr = elf_errno();
1127a85fe12eSEd Maste 		if (elferr != 0)
1128a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1129a85fe12eSEd Maste 			    elf_errmsg(elferr));
1130a85fe12eSEd Maste 	}
1131a85fe12eSEd Maste 	putchar('\n');
1132a85fe12eSEd Maste }
1133a85fe12eSEd Maste 
1134a85fe12eSEd Maste static void *
read_section(struct section * s,size_t * size)1135a85fe12eSEd Maste read_section(struct section *s, size_t *size)
1136a85fe12eSEd Maste {
1137a85fe12eSEd Maste 	Elf_Data	*id;
1138a85fe12eSEd Maste 	char		*b;
1139a85fe12eSEd Maste 	size_t		 sz;
1140a85fe12eSEd Maste 	int		 elferr;
1141a85fe12eSEd Maste 
1142a85fe12eSEd Maste 	sz = 0;
1143a85fe12eSEd Maste 	b = NULL;
1144a85fe12eSEd Maste 	id = NULL;
1145839529caSEd Maste 	while ((id = elf_getdata(s->is, id)) != NULL ||
1146839529caSEd Maste 	    (id = elf_rawdata(s->is, id)) != NULL) {
1147839529caSEd Maste 		(void) elf_errno();
1148a85fe12eSEd Maste 		if (b == NULL)
1149a85fe12eSEd Maste 			b = malloc(id->d_size);
1150a85fe12eSEd Maste 		else
1151f2530c80SMark Johnston 			b = realloc(b, sz + id->d_size);
1152a85fe12eSEd Maste 		if (b == NULL)
1153a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc or realloc failed");
1154a85fe12eSEd Maste 
1155a85fe12eSEd Maste 		memcpy(&b[sz], id->d_buf, id->d_size);
1156a85fe12eSEd Maste 		sz += id->d_size;
1157a85fe12eSEd Maste 	}
1158a85fe12eSEd Maste 	elferr = elf_errno();
1159a85fe12eSEd Maste 	if (elferr != 0)
1160a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1161a85fe12eSEd Maste 		    elf_errmsg(elferr));
1162a85fe12eSEd Maste 
1163a85fe12eSEd Maste 	*size = sz;
1164a85fe12eSEd Maste 
1165a85fe12eSEd Maste 	return (b);
1166a85fe12eSEd Maste }
1167a85fe12eSEd Maste 
1168a85fe12eSEd Maste void
copy_shdr(struct elfcopy * ecp,struct section * s,const char * name,int copy,int sec_flags)1169a85fe12eSEd Maste copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy,
1170a85fe12eSEd Maste     int sec_flags)
1171a85fe12eSEd Maste {
1172a85fe12eSEd Maste 	GElf_Shdr ish, osh;
1173a85fe12eSEd Maste 
1174a85fe12eSEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
1175839529caSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1176a85fe12eSEd Maste 		    elf_errmsg(-1));
1177a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
1178839529caSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1179a85fe12eSEd Maste 		    elf_errmsg(-1));
1180a85fe12eSEd Maste 
1181a85fe12eSEd Maste 	if (copy)
1182a85fe12eSEd Maste 		(void) memcpy(&osh, &ish, sizeof(ish));
1183a85fe12eSEd Maste 	else {
1184a85fe12eSEd Maste 		osh.sh_type		= s->type;
1185a85fe12eSEd Maste 		osh.sh_addr		= s->vma;
1186a85fe12eSEd Maste 		osh.sh_offset		= s->off;
1187a85fe12eSEd Maste 		osh.sh_size		= s->sz;
1188a85fe12eSEd Maste 		osh.sh_link		= ish.sh_link;
1189a85fe12eSEd Maste 		osh.sh_info		= ish.sh_info;
1190a85fe12eSEd Maste 		osh.sh_addralign	= s->align;
1191a85fe12eSEd Maste 		osh.sh_entsize		= ish.sh_entsize;
1192a85fe12eSEd Maste 
1193a85fe12eSEd Maste 		if (sec_flags) {
1194a85fe12eSEd Maste 			osh.sh_flags = 0;
1195839529caSEd Maste 			if (sec_flags & SF_ALLOC)
1196a85fe12eSEd Maste 				osh.sh_flags |= SHF_ALLOC;
1197a85fe12eSEd Maste 			if ((sec_flags & SF_READONLY) == 0)
1198a85fe12eSEd Maste 				osh.sh_flags |= SHF_WRITE;
1199a85fe12eSEd Maste 			if (sec_flags & SF_CODE)
1200a85fe12eSEd Maste 				osh.sh_flags |= SHF_EXECINSTR;
1201839529caSEd Maste 			if ((sec_flags & SF_CONTENTS) &&
1202839529caSEd Maste 			    s->type == SHT_NOBITS && s->sz > 0) {
1203839529caSEd Maste 				/*
1204839529caSEd Maste 				 * Convert SHT_NOBITS section to section with
1205839529caSEd Maste 				 * (zero'ed) content on file.
1206839529caSEd Maste 				 */
1207839529caSEd Maste 				osh.sh_type = s->type = SHT_PROGBITS;
1208839529caSEd Maste 				if ((s->buf = calloc(1, s->sz)) == NULL)
1209839529caSEd Maste 					err(EXIT_FAILURE, "malloc failed");
1210839529caSEd Maste 				s->nocopy = 1;
1211839529caSEd Maste 			}
12123ef90571SEd Maste 		} else {
1213a85fe12eSEd Maste 			osh.sh_flags = ish.sh_flags;
1214839529caSEd Maste 			/*
1215839529caSEd Maste 			 * Newer binutils as(1) emits the section flag
1216839529caSEd Maste 			 * SHF_INFO_LINK for relocation sections. elfcopy
1217839529caSEd Maste 			 * emits this flag in the output section if it's
1218839529caSEd Maste 			 * missing in the input section, to remain compatible
1219839529caSEd Maste 			 * with binutils.
1220839529caSEd Maste 			 */
12213ef90571SEd Maste 			if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)
12223ef90571SEd Maste 				osh.sh_flags |= SHF_INFO_LINK;
12233ef90571SEd Maste 		}
1224a85fe12eSEd Maste 	}
1225a85fe12eSEd Maste 
1226a85fe12eSEd Maste 	if (name == NULL)
1227a85fe12eSEd Maste 		add_to_shstrtab(ecp, s->name);
1228a85fe12eSEd Maste 	else
1229a85fe12eSEd Maste 		add_to_shstrtab(ecp, name);
1230a85fe12eSEd Maste 
1231a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &osh))
1232a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
1233a85fe12eSEd Maste 		    elf_errmsg(-1));
1234a85fe12eSEd Maste }
1235a85fe12eSEd Maste 
1236a85fe12eSEd Maste void
copy_data(struct section * s)1237a85fe12eSEd Maste copy_data(struct section *s)
1238a85fe12eSEd Maste {
1239a85fe12eSEd Maste 	Elf_Data	*id, *od;
1240a85fe12eSEd Maste 	int		 elferr;
1241a85fe12eSEd Maste 
1242a85fe12eSEd Maste 	if (s->nocopy && s->buf == NULL)
1243a85fe12eSEd Maste 		return;
1244a85fe12eSEd Maste 
1245a85fe12eSEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL) {
1246839529caSEd Maste 		(void) elf_errno();
1247839529caSEd Maste 		if ((id = elf_rawdata(s->is, NULL)) == NULL) {
1248a85fe12eSEd Maste 			elferr = elf_errno();
1249a85fe12eSEd Maste 			if (elferr != 0)
1250839529caSEd Maste 				errx(EXIT_FAILURE, "failed to read section:"
1251839529caSEd Maste 				    " %s", s->name);
1252a85fe12eSEd Maste 			return;
1253a85fe12eSEd Maste 		}
1254839529caSEd Maste 	}
1255a85fe12eSEd Maste 
1256a85fe12eSEd Maste 	if ((od = elf_newdata(s->os)) == NULL)
1257a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1258a85fe12eSEd Maste 		    elf_errmsg(-1));
1259a85fe12eSEd Maste 
1260a85fe12eSEd Maste 	if (s->nocopy) {
1261a85fe12eSEd Maste 		/* Use s->buf as content if s->nocopy is set. */
1262a85fe12eSEd Maste 		od->d_align	= id->d_align;
1263a85fe12eSEd Maste 		od->d_off	= 0;
1264a85fe12eSEd Maste 		od->d_buf	= s->buf;
1265a85fe12eSEd Maste 		od->d_type	= id->d_type;
1266a85fe12eSEd Maste 		od->d_size	= s->sz;
1267a85fe12eSEd Maste 		od->d_version	= id->d_version;
1268a85fe12eSEd Maste 	} else {
1269a85fe12eSEd Maste 		od->d_align	= id->d_align;
1270a85fe12eSEd Maste 		od->d_off	= id->d_off;
1271a85fe12eSEd Maste 		od->d_buf	= id->d_buf;
1272a85fe12eSEd Maste 		od->d_type	= id->d_type;
1273a85fe12eSEd Maste 		od->d_size	= id->d_size;
1274a85fe12eSEd Maste 		od->d_version	= id->d_version;
1275a85fe12eSEd Maste 	}
12764a85c691SEd Maste 
12774a85c691SEd Maste 	/*
12784a85c691SEd Maste 	 * Alignment Fixup. libelf does not allow the alignment for
12794a85c691SEd Maste 	 * Elf_Data descriptor to be set to 0. In this case we workaround
12804a85c691SEd Maste 	 * it by setting the alignment to 1.
12814a85c691SEd Maste 	 *
12824a85c691SEd Maste 	 * According to the ELF ABI, alignment 0 and 1 has the same
12834a85c691SEd Maste 	 * meaning: the section has no alignment constraints.
12844a85c691SEd Maste 	 */
12854a85c691SEd Maste 	if (od->d_align == 0)
12864a85c691SEd Maste 		od->d_align = 1;
1287a85fe12eSEd Maste }
1288a85fe12eSEd Maste 
1289a85fe12eSEd Maste struct section *
create_external_section(struct elfcopy * ecp,const char * name,char * newname,void * buf,uint64_t size,uint64_t off,uint64_t stype,Elf_Type dtype,uint64_t flags,uint64_t align,uint64_t vma,int loadable)1290a85fe12eSEd Maste create_external_section(struct elfcopy *ecp, const char *name, char *newname,
1291a85fe12eSEd Maste     void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype,
1292a85fe12eSEd Maste     uint64_t flags, uint64_t align, uint64_t vma, int loadable)
1293a85fe12eSEd Maste {
1294a85fe12eSEd Maste 	struct section	*s;
1295a85fe12eSEd Maste 	Elf_Scn		*os;
1296a85fe12eSEd Maste 	Elf_Data	*od;
1297a85fe12eSEd Maste 	GElf_Shdr	 osh;
1298a85fe12eSEd Maste 
1299a85fe12eSEd Maste 	if ((os = elf_newscn(ecp->eout)) == NULL)
1300a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newscn() failed: %s",
1301a85fe12eSEd Maste 		    elf_errmsg(-1));
1302a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
1303a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
1304a85fe12eSEd Maste 	s->name = name;
1305a85fe12eSEd Maste 	s->newname = newname;	/* needs to be free()'ed */
1306a85fe12eSEd Maste 	s->off = off;
1307a85fe12eSEd Maste 	s->sz = size;
1308a85fe12eSEd Maste 	s->vma = vma;
1309a85fe12eSEd Maste 	s->align = align;
1310a85fe12eSEd Maste 	s->loadable = loadable;
1311a85fe12eSEd Maste 	s->is = NULL;
1312a85fe12eSEd Maste 	s->os = os;
1313a85fe12eSEd Maste 	s->type = stype;
1314a85fe12eSEd Maste 	s->nocopy = 1;
1315a85fe12eSEd Maste 	insert_to_sec_list(ecp, s, 1);
1316a85fe12eSEd Maste 
1317a85fe12eSEd Maste 	if (gelf_getshdr(os, &osh) == NULL)
1318a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1319a85fe12eSEd Maste 		    elf_errmsg(-1));
1320a85fe12eSEd Maste 	osh.sh_flags = flags;
1321a85fe12eSEd Maste 	osh.sh_type = s->type;
1322a85fe12eSEd Maste 	osh.sh_addr = s->vma;
1323a85fe12eSEd Maste 	osh.sh_addralign = s->align;
1324a85fe12eSEd Maste 	if (!gelf_update_shdr(os, &osh))
1325a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1326a85fe12eSEd Maste 		    elf_errmsg(-1));
1327a85fe12eSEd Maste 	add_to_shstrtab(ecp, name);
1328a85fe12eSEd Maste 
1329a85fe12eSEd Maste 	if (buf != NULL && size != 0) {
1330a85fe12eSEd Maste 		if ((od = elf_newdata(os)) == NULL)
1331a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1332a85fe12eSEd Maste 			    elf_errmsg(-1));
1333a85fe12eSEd Maste 		od->d_align = align;
1334a85fe12eSEd Maste 		od->d_off = 0;
1335a85fe12eSEd Maste 		od->d_buf = buf;
1336a85fe12eSEd Maste 		od->d_size = size;
1337a85fe12eSEd Maste 		od->d_type = dtype;
1338a85fe12eSEd Maste 		od->d_version = EV_CURRENT;
1339a85fe12eSEd Maste 	}
1340a85fe12eSEd Maste 
1341a85fe12eSEd Maste 	/*
1342a85fe12eSEd Maste 	 * Clear SYMTAB_INTACT, as we probably need to update/add new
1343a85fe12eSEd Maste 	 * STT_SECTION symbols into the symbol table.
1344a85fe12eSEd Maste 	 */
1345a85fe12eSEd Maste 	ecp->flags &= ~SYMTAB_INTACT;
1346a85fe12eSEd Maste 
1347a85fe12eSEd Maste 	return (s);
1348a85fe12eSEd Maste }
1349a85fe12eSEd Maste 
1350a85fe12eSEd Maste /*
1351a85fe12eSEd Maste  * Insert sections specified by --add-section to the end of section list.
1352a85fe12eSEd Maste  */
1353a85fe12eSEd Maste static void
insert_sections(struct elfcopy * ecp)1354a85fe12eSEd Maste insert_sections(struct elfcopy *ecp)
1355a85fe12eSEd Maste {
1356a85fe12eSEd Maste 	struct sec_add	*sa;
1357a85fe12eSEd Maste 	struct section	*s;
1358a85fe12eSEd Maste 	size_t		 off;
1359839529caSEd Maste 	uint64_t	 stype;
1360a85fe12eSEd Maste 
1361a85fe12eSEd Maste 	/* Put these sections in the end of current list. */
1362a85fe12eSEd Maste 	off = 0;
1363a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1364a85fe12eSEd Maste 		if (s->type != SHT_NOBITS && s->type != SHT_NULL)
1365a85fe12eSEd Maste 			off = s->off + s->sz;
1366a85fe12eSEd Maste 		else
1367a85fe12eSEd Maste 			off = s->off;
1368a85fe12eSEd Maste 	}
1369a85fe12eSEd Maste 
1370a85fe12eSEd Maste 	STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) {
1371a85fe12eSEd Maste 
1372a85fe12eSEd Maste 		/* TODO: Add section header vma/lma, flag changes here */
1373a85fe12eSEd Maste 
1374839529caSEd Maste 		/*
1375839529caSEd Maste 		 * The default section type for user added section is
1376839529caSEd Maste 		 * SHT_PROGBITS. If the section name match certain patterns,
1377839529caSEd Maste 		 * elfcopy will try to set a more appropriate section type.
1378839529caSEd Maste 		 * However, data type is always set to ELF_T_BYTE and no
1379839529caSEd Maste 		 * translation is performed by libelf.
1380839529caSEd Maste 		 */
1381839529caSEd Maste 		stype = SHT_PROGBITS;
1382839529caSEd Maste 		if (strcmp(sa->name, ".note") == 0 ||
1383839529caSEd Maste 		    strncmp(sa->name, ".note.", strlen(".note.")) == 0)
1384839529caSEd Maste 			stype = SHT_NOTE;
1385839529caSEd Maste 
1386a85fe12eSEd Maste 		(void) create_external_section(ecp, sa->name, NULL, sa->content,
1387839529caSEd Maste 		    sa->size, off, stype, ELF_T_BYTE, 0, 1, 0, 0);
1388a85fe12eSEd Maste 	}
1389a85fe12eSEd Maste }
1390a85fe12eSEd Maste 
1391a85fe12eSEd Maste void
add_to_shstrtab(struct elfcopy * ecp,const char * name)1392a85fe12eSEd Maste add_to_shstrtab(struct elfcopy *ecp, const char *name)
1393a85fe12eSEd Maste {
1394a85fe12eSEd Maste 
1395bc589b72SMark Johnston 	if (elftc_string_table_insert(ecp->shstrtab->strtab, name) == 0)
1396bc589b72SMark Johnston 		errx(EXIT_FAILURE, "elftc_string_table_insert failed");
1397a85fe12eSEd Maste }
1398a85fe12eSEd Maste 
1399a85fe12eSEd Maste void
update_shdr(struct elfcopy * ecp,int update_link)1400a85fe12eSEd Maste update_shdr(struct elfcopy *ecp, int update_link)
1401a85fe12eSEd Maste {
1402a85fe12eSEd Maste 	struct section	*s;
1403a85fe12eSEd Maste 	GElf_Shdr	 osh;
1404a85fe12eSEd Maste 	int		 elferr;
1405a85fe12eSEd Maste 
1406bc589b72SMark Johnston 	/* Finalize the section name string table (.shstrtab). */
1407bc589b72SMark Johnston 	set_shstrtab(ecp);
1408bc589b72SMark Johnston 
1409a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1410a85fe12eSEd Maste 		if (s->pseudo)
1411a85fe12eSEd Maste 			continue;
1412a85fe12eSEd Maste 
1413a85fe12eSEd Maste 		if (gelf_getshdr(s->os, &osh) == NULL)
1414839529caSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
1415a85fe12eSEd Maste 			    elf_errmsg(-1));
1416a85fe12eSEd Maste 
1417a85fe12eSEd Maste 		/* Find section name in string table and set sh_name. */
1418bc589b72SMark Johnston 		osh.sh_name = elftc_string_table_lookup(ecp->shstrtab->strtab,
1419bc589b72SMark Johnston 		    s->name);
1420a85fe12eSEd Maste 
1421a85fe12eSEd Maste 		/*
1422a85fe12eSEd Maste 		 * sh_link needs to be updated, since the index of the
1423a85fe12eSEd Maste 		 * linked section might have changed.
1424a85fe12eSEd Maste 		 */
1425a85fe12eSEd Maste 		if (update_link && osh.sh_link != 0)
1426a85fe12eSEd Maste 			osh.sh_link = ecp->secndx[osh.sh_link];
1427a85fe12eSEd Maste 
1428a85fe12eSEd Maste 		/*
1429a85fe12eSEd Maste 		 * sh_info of relocation section links to the section to which
1430a85fe12eSEd Maste 		 * its relocation info applies. So it may need update as well.
1431a85fe12eSEd Maste 		 */
1432a85fe12eSEd Maste 		if ((s->type == SHT_REL || s->type == SHT_RELA) &&
1433a85fe12eSEd Maste 		    osh.sh_info != 0)
1434a85fe12eSEd Maste 			osh.sh_info = ecp->secndx[osh.sh_info];
1435a85fe12eSEd Maste 
1436b00fe64fSEd Maste 		/*
1437b00fe64fSEd Maste 		 * sh_info of SHT_GROUP section needs to point to the correct
1438b00fe64fSEd Maste 		 * string in the symbol table.
1439b00fe64fSEd Maste 		 */
1440b00fe64fSEd Maste 		if (s->type == SHT_GROUP && (ecp->flags & SYMTAB_EXIST) &&
1441b00fe64fSEd Maste 		    (ecp->flags & SYMTAB_INTACT) == 0)
1442b00fe64fSEd Maste 			osh.sh_info = ecp->symndx[osh.sh_info];
1443b00fe64fSEd Maste 
1444a85fe12eSEd Maste 		if (!gelf_update_shdr(s->os, &osh))
1445a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1446a85fe12eSEd Maste 			    elf_errmsg(-1));
1447a85fe12eSEd Maste 	}
1448a85fe12eSEd Maste 	elferr = elf_errno();
1449a85fe12eSEd Maste 	if (elferr != 0)
1450a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
1451a85fe12eSEd Maste 		    elf_errmsg(elferr));
1452a85fe12eSEd Maste }
1453a85fe12eSEd Maste 
1454a85fe12eSEd Maste void
init_shstrtab(struct elfcopy * ecp)1455a85fe12eSEd Maste init_shstrtab(struct elfcopy *ecp)
1456a85fe12eSEd Maste {
1457c8b057f4SMark Johnston 	Elf_Scn *shstrtab;
1458c8b057f4SMark Johnston 	GElf_Shdr shdr;
1459a85fe12eSEd Maste 	struct section *s;
1460c8b057f4SMark Johnston 	size_t indx, sizehint;
1461c8b057f4SMark Johnston 
14620070b575SMark Johnston 	if (elf_getshdrstrndx(ecp->ein, &indx) == 0) {
1463c8b057f4SMark Johnston 		shstrtab = elf_getscn(ecp->ein, indx);
1464c8b057f4SMark Johnston 		if (shstrtab == NULL)
1465c8b057f4SMark Johnston 			errx(EXIT_FAILURE, "elf_getscn failed: %s",
1466c8b057f4SMark Johnston 			    elf_errmsg(-1));
1467c8b057f4SMark Johnston 		if (gelf_getshdr(shstrtab, &shdr) != &shdr)
1468c8b057f4SMark Johnston 			errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
1469c8b057f4SMark Johnston 			    elf_errmsg(-1));
1470c8b057f4SMark Johnston 		sizehint = shdr.sh_size;
1471c8b057f4SMark Johnston 	} else {
14720070b575SMark Johnston 		/* Clear the error from elf_getshdrstrndx(3). */
14730070b575SMark Johnston 		(void)elf_errno();
1474c8b057f4SMark Johnston 		sizehint = 0;
1475c8b057f4SMark Johnston 	}
1476a85fe12eSEd Maste 
1477a85fe12eSEd Maste 	if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL)
1478a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
1479a85fe12eSEd Maste 	s = ecp->shstrtab;
1480a85fe12eSEd Maste 	s->name = ".shstrtab";
1481a85fe12eSEd Maste 	s->is = NULL;
1482a85fe12eSEd Maste 	s->sz = 0;
1483a85fe12eSEd Maste 	s->align = 1;
1484a85fe12eSEd Maste 	s->loadable = 0;
1485a85fe12eSEd Maste 	s->type = SHT_STRTAB;
1486a85fe12eSEd Maste 	s->vma = 0;
1487c8b057f4SMark Johnston 	s->strtab = elftc_string_table_create(sizehint);
14889ef62fdbSEd Maste 
1489bc589b72SMark Johnston 	add_to_shstrtab(ecp, "");
1490bc589b72SMark Johnston 	add_to_shstrtab(ecp, ".symtab");
1491bc589b72SMark Johnston 	add_to_shstrtab(ecp, ".strtab");
1492bc589b72SMark Johnston 	add_to_shstrtab(ecp, ".shstrtab");
1493a85fe12eSEd Maste }
1494a85fe12eSEd Maste 
1495bc589b72SMark Johnston static void
set_shstrtab(struct elfcopy * ecp)1496a85fe12eSEd Maste set_shstrtab(struct elfcopy *ecp)
1497a85fe12eSEd Maste {
1498a85fe12eSEd Maste 	struct section	*s;
1499a85fe12eSEd Maste 	Elf_Data	*data;
1500a85fe12eSEd Maste 	GElf_Shdr	 sh;
1501bc589b72SMark Johnston 	const char	*image;
1502bc589b72SMark Johnston 	size_t		 sz;
1503a85fe12eSEd Maste 
1504a85fe12eSEd Maste 	s = ecp->shstrtab;
1505a85fe12eSEd Maste 
1506619ba3b4SEd Maste 	if (s->os == NULL) {
1507619ba3b4SEd Maste 		/* Input object does not contain .shstrtab section */
1508619ba3b4SEd Maste 		if ((s->os = elf_newscn(ecp->eout)) == NULL)
1509619ba3b4SEd Maste 			errx(EXIT_FAILURE, "elf_newscn failed: %s",
1510619ba3b4SEd Maste 			    elf_errmsg(-1));
1511619ba3b4SEd Maste 		insert_to_sec_list(ecp, s, 1);
1512619ba3b4SEd Maste 	}
1513619ba3b4SEd Maste 
1514a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &sh) == NULL)
1515839529caSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1516a85fe12eSEd Maste 		    elf_errmsg(-1));
1517a85fe12eSEd Maste 	sh.sh_addr	= 0;
1518a85fe12eSEd Maste 	sh.sh_addralign	= 1;
1519a85fe12eSEd Maste 	sh.sh_offset	= s->off;
1520a85fe12eSEd Maste 	sh.sh_type	= SHT_STRTAB;
1521a85fe12eSEd Maste 	sh.sh_flags	= 0;
1522a85fe12eSEd Maste 	sh.sh_entsize	= 0;
1523a85fe12eSEd Maste 	sh.sh_info	= 0;
1524a85fe12eSEd Maste 	sh.sh_link	= 0;
1525a85fe12eSEd Maste 
1526a85fe12eSEd Maste 	if ((data = elf_newdata(s->os)) == NULL)
1527a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1528a85fe12eSEd Maste 		    elf_errmsg(-1));
1529a85fe12eSEd Maste 
1530a85fe12eSEd Maste 	/*
1531a85fe12eSEd Maste 	 * If we don't have a symbol table, skip those a few bytes
1532a85fe12eSEd Maste 	 * which are reserved for this in the beginning of shstrtab.
1533a85fe12eSEd Maste 	 */
1534a85fe12eSEd Maste 	if (!(ecp->flags & SYMTAB_EXIST)) {
1535bc589b72SMark Johnston 		elftc_string_table_remove(s->strtab, ".symtab");
1536bc589b72SMark Johnston 		elftc_string_table_remove(s->strtab, ".strtab");
1537a85fe12eSEd Maste 	}
1538a85fe12eSEd Maste 
1539bc589b72SMark Johnston 	image = elftc_string_table_image(s->strtab, &sz);
1540bc589b72SMark Johnston 	s->sz = sz;
1541bc589b72SMark Johnston 
1542bc589b72SMark Johnston 	sh.sh_size	= sz;
1543a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &sh))
1544a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1545a85fe12eSEd Maste 		    elf_errmsg(-1));
1546a85fe12eSEd Maste 
1547a85fe12eSEd Maste 	data->d_align	= 1;
1548bc589b72SMark Johnston 	data->d_buf	= (void *)(uintptr_t)image;
1549bc589b72SMark Johnston 	data->d_size	= sz;
1550a85fe12eSEd Maste 	data->d_off	= 0;
1551a85fe12eSEd Maste 	data->d_type	= ELF_T_BYTE;
1552a85fe12eSEd Maste 	data->d_version	= EV_CURRENT;
1553a85fe12eSEd Maste 
1554a85fe12eSEd Maste 	if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os)))
1555a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s",
1556a85fe12eSEd Maste 		     elf_errmsg(-1));
1557a85fe12eSEd Maste }
1558a85fe12eSEd Maste 
1559a85fe12eSEd Maste void
add_section(struct elfcopy * ecp,const char * arg)1560a85fe12eSEd Maste add_section(struct elfcopy *ecp, const char *arg)
1561a85fe12eSEd Maste {
1562a85fe12eSEd Maste 	struct sec_add	*sa;
1563a85fe12eSEd Maste 	struct stat	 sb;
1564a85fe12eSEd Maste 	const char	*s, *fn;
1565a85fe12eSEd Maste 	FILE		*fp;
1566a85fe12eSEd Maste 	int		 len;
1567a85fe12eSEd Maste 
1568a85fe12eSEd Maste 	if ((s = strchr(arg, '=')) == NULL)
1569a85fe12eSEd Maste 		errx(EXIT_FAILURE,
1570a85fe12eSEd Maste 		    "illegal format for --add-section option");
1571a85fe12eSEd Maste 	if ((sa = malloc(sizeof(*sa))) == NULL)
1572a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1573a85fe12eSEd Maste 
1574a85fe12eSEd Maste 	len = s - arg;
1575a85fe12eSEd Maste 	if ((sa->name = malloc(len + 1)) == NULL)
1576a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1577a85fe12eSEd Maste 	strncpy(sa->name, arg, len);
1578a85fe12eSEd Maste 	sa->name[len] = '\0';
1579a85fe12eSEd Maste 
1580a85fe12eSEd Maste 	fn = s + 1;
1581a85fe12eSEd Maste 	if (stat(fn, &sb) == -1)
1582a85fe12eSEd Maste 		err(EXIT_FAILURE, "stat failed");
1583a85fe12eSEd Maste 	sa->size = sb.st_size;
1584839529caSEd Maste 	if (sa->size > 0) {
1585a85fe12eSEd Maste 		if ((sa->content = malloc(sa->size)) == NULL)
1586a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
1587a85fe12eSEd Maste 		if ((fp = fopen(fn, "r")) == NULL)
1588a85fe12eSEd Maste 			err(EXIT_FAILURE, "can not open %s", fn);
1589a85fe12eSEd Maste 		if (fread(sa->content, 1, sa->size, fp) == 0 ||
1590a85fe12eSEd Maste 		    ferror(fp))
1591a85fe12eSEd Maste 			err(EXIT_FAILURE, "fread failed");
1592a85fe12eSEd Maste 		fclose(fp);
1593839529caSEd Maste 	} else
1594839529caSEd Maste 		sa->content = NULL;
1595a85fe12eSEd Maste 
1596a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1597a85fe12eSEd Maste 	ecp->flags |= SEC_ADD;
1598a85fe12eSEd Maste }
1599a85fe12eSEd Maste 
1600a85fe12eSEd Maste void
free_sec_add(struct elfcopy * ecp)1601a85fe12eSEd Maste free_sec_add(struct elfcopy *ecp)
1602a85fe12eSEd Maste {
1603a85fe12eSEd Maste 	struct sec_add *sa, *sa_temp;
1604a85fe12eSEd Maste 
1605a85fe12eSEd Maste 	STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) {
1606a85fe12eSEd Maste 		STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list);
1607a85fe12eSEd Maste 		free(sa->name);
1608a85fe12eSEd Maste 		free(sa->content);
1609a85fe12eSEd Maste 		free(sa);
1610a85fe12eSEd Maste 	}
1611a85fe12eSEd Maste }
1612a85fe12eSEd Maste 
1613a85fe12eSEd Maste static void
add_gnu_debuglink(struct elfcopy * ecp)1614a85fe12eSEd Maste add_gnu_debuglink(struct elfcopy *ecp)
1615a85fe12eSEd Maste {
1616a85fe12eSEd Maste 	struct sec_add	*sa;
1617a85fe12eSEd Maste 	struct stat	 sb;
1618a85fe12eSEd Maste 	FILE		*fp;
1619a85fe12eSEd Maste 	char		*fnbase, *buf;
1620a85fe12eSEd Maste 	int		 crc_off;
1621a85fe12eSEd Maste 	int		 crc;
1622a85fe12eSEd Maste 
1623a85fe12eSEd Maste 	if (ecp->debuglink == NULL)
1624a85fe12eSEd Maste 		return;
1625a85fe12eSEd Maste 
1626a85fe12eSEd Maste 	/* Read debug file content. */
1627a85fe12eSEd Maste 	if ((sa = malloc(sizeof(*sa))) == NULL)
1628a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1629a85fe12eSEd Maste 	if ((sa->name = strdup(".gnu_debuglink")) == NULL)
1630a85fe12eSEd Maste 		err(EXIT_FAILURE, "strdup failed");
1631a85fe12eSEd Maste 	if (stat(ecp->debuglink, &sb) == -1)
1632a85fe12eSEd Maste 		err(EXIT_FAILURE, "stat failed");
1633f5e9c916SEd Maste 	if (sb.st_size == 0)
1634f5e9c916SEd Maste 		errx(EXIT_FAILURE, "empty debug link target %s",
1635f5e9c916SEd Maste 		    ecp->debuglink);
1636a85fe12eSEd Maste 	if ((buf = malloc(sb.st_size)) == NULL)
1637a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1638a85fe12eSEd Maste 	if ((fp = fopen(ecp->debuglink, "r")) == NULL)
1639a85fe12eSEd Maste 		err(EXIT_FAILURE, "can not open %s", ecp->debuglink);
1640a85fe12eSEd Maste 	if (fread(buf, 1, sb.st_size, fp) == 0 ||
1641a85fe12eSEd Maste 	    ferror(fp))
1642a85fe12eSEd Maste 		err(EXIT_FAILURE, "fread failed");
1643a85fe12eSEd Maste 	fclose(fp);
1644a85fe12eSEd Maste 
1645a85fe12eSEd Maste 	/* Calculate crc checksum.  */
1646a85fe12eSEd Maste 	crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF);
1647a85fe12eSEd Maste 	free(buf);
1648a85fe12eSEd Maste 
1649a85fe12eSEd Maste 	/* Calculate section size and the offset to store crc checksum. */
1650a85fe12eSEd Maste 	if ((fnbase = basename(ecp->debuglink)) == NULL)
1651a85fe12eSEd Maste 		err(EXIT_FAILURE, "basename failed");
1652a85fe12eSEd Maste 	crc_off = roundup(strlen(fnbase) + 1, 4);
1653a85fe12eSEd Maste 	sa->size = crc_off + 4;
1654a85fe12eSEd Maste 
1655a85fe12eSEd Maste 	/* Section content. */
1656a85fe12eSEd Maste 	if ((sa->content = calloc(1, sa->size)) == NULL)
1657a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1658a85fe12eSEd Maste 	strncpy(sa->content, fnbase, strlen(fnbase));
1659a85fe12eSEd Maste 	if (ecp->oed == ELFDATA2LSB) {
1660a85fe12eSEd Maste 		sa->content[crc_off] = crc & 0xFF;
1661a85fe12eSEd Maste 		sa->content[crc_off + 1] = (crc >> 8) & 0xFF;
1662a85fe12eSEd Maste 		sa->content[crc_off + 2] = (crc >> 16) & 0xFF;
1663a85fe12eSEd Maste 		sa->content[crc_off + 3] = crc >> 24;
1664a85fe12eSEd Maste 	} else {
1665a85fe12eSEd Maste 		sa->content[crc_off] = crc >> 24;
1666a85fe12eSEd Maste 		sa->content[crc_off + 1] = (crc >> 16) & 0xFF;
1667a85fe12eSEd Maste 		sa->content[crc_off + 2] = (crc >> 8) & 0xFF;
1668a85fe12eSEd Maste 		sa->content[crc_off + 3] = crc & 0xFF;
1669a85fe12eSEd Maste 	}
1670a85fe12eSEd Maste 
1671a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1672a85fe12eSEd Maste 	ecp->flags |= SEC_ADD;
1673a85fe12eSEd Maste }
1674a85fe12eSEd Maste 
1675a85fe12eSEd Maste static uint32_t crctable[256] =
1676a85fe12eSEd Maste {
1677a85fe12eSEd Maste 	0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
1678a85fe12eSEd Maste 	0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
1679a85fe12eSEd Maste 	0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
1680a85fe12eSEd Maste 	0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
1681a85fe12eSEd Maste 	0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
1682a85fe12eSEd Maste 	0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
1683a85fe12eSEd Maste 	0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
1684a85fe12eSEd Maste 	0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
1685a85fe12eSEd Maste 	0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
1686a85fe12eSEd Maste 	0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
1687a85fe12eSEd Maste 	0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
1688a85fe12eSEd Maste 	0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
1689a85fe12eSEd Maste 	0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
1690a85fe12eSEd Maste 	0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
1691a85fe12eSEd Maste 	0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
1692a85fe12eSEd Maste 	0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
1693a85fe12eSEd Maste 	0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
1694a85fe12eSEd Maste 	0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
1695a85fe12eSEd Maste 	0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
1696a85fe12eSEd Maste 	0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
1697a85fe12eSEd Maste 	0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
1698a85fe12eSEd Maste 	0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
1699a85fe12eSEd Maste 	0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
1700a85fe12eSEd Maste 	0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
1701a85fe12eSEd Maste 	0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
1702a85fe12eSEd Maste 	0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
1703a85fe12eSEd Maste 	0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
1704a85fe12eSEd Maste 	0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
1705a85fe12eSEd Maste 	0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
1706a85fe12eSEd Maste 	0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
1707a85fe12eSEd Maste 	0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
1708a85fe12eSEd Maste 	0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
1709a85fe12eSEd Maste 	0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
1710a85fe12eSEd Maste 	0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
1711a85fe12eSEd Maste 	0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
1712a85fe12eSEd Maste 	0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
1713a85fe12eSEd Maste 	0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
1714a85fe12eSEd Maste 	0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
1715a85fe12eSEd Maste 	0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
1716a85fe12eSEd Maste 	0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
1717a85fe12eSEd Maste 	0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
1718a85fe12eSEd Maste 	0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
1719a85fe12eSEd Maste 	0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
1720a85fe12eSEd Maste 	0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
1721a85fe12eSEd Maste 	0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
1722a85fe12eSEd Maste 	0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
1723a85fe12eSEd Maste 	0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
1724a85fe12eSEd Maste 	0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
1725a85fe12eSEd Maste 	0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
1726a85fe12eSEd Maste 	0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
1727a85fe12eSEd Maste 	0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
1728a85fe12eSEd Maste 	0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
1729a85fe12eSEd Maste 	0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
1730a85fe12eSEd Maste 	0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
1731a85fe12eSEd Maste 	0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
1732a85fe12eSEd Maste 	0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
1733a85fe12eSEd Maste 	0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
1734a85fe12eSEd Maste 	0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
1735a85fe12eSEd Maste 	0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
1736a85fe12eSEd Maste 	0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
1737a85fe12eSEd Maste 	0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
1738a85fe12eSEd Maste 	0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
1739a85fe12eSEd Maste 	0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
1740a85fe12eSEd Maste 	0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
1741a85fe12eSEd Maste };
1742a85fe12eSEd Maste 
1743a85fe12eSEd Maste static uint32_t
calc_crc32(const char * p,size_t len,uint32_t crc)1744a85fe12eSEd Maste calc_crc32(const char *p, size_t len, uint32_t crc)
1745a85fe12eSEd Maste {
1746a85fe12eSEd Maste 	uint32_t i;
1747a85fe12eSEd Maste 
1748a85fe12eSEd Maste 	for (i = 0; i < len; i++) {
1749a85fe12eSEd Maste 		crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);
1750a85fe12eSEd Maste 	}
1751a85fe12eSEd Maste 
1752a85fe12eSEd Maste 	return (crc ^ 0xFFFFFFFF);
1753a85fe12eSEd Maste }
1754