xref: /freebsd-src/contrib/elftoolchain/elfcopy/sections.c (revision aee4c74cdd59cd847af5a02de8c8e93bb31ac9fa)
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>
31a85fe12eSEd Maste #include <stdio.h>
32a85fe12eSEd Maste #include <stdlib.h>
33a85fe12eSEd Maste #include <string.h>
34a85fe12eSEd Maste 
35a85fe12eSEd Maste #include "elfcopy.h"
36a85fe12eSEd Maste 
37b6b6f9ccSEd Maste ELFTC_VCSID("$Id: sections.c 3443 2016-04-15 18:57:54Z kaiwang27 $");
38a85fe12eSEd Maste 
39a85fe12eSEd Maste static void	add_gnu_debuglink(struct elfcopy *ecp);
40a85fe12eSEd Maste static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc);
41a85fe12eSEd Maste static void	check_section_rename(struct elfcopy *ecp, struct section *s);
42*aee4c74cSEd Maste static void	filter_reloc(struct elfcopy *ecp, struct section *s);
43a85fe12eSEd Maste static int	get_section_flags(struct elfcopy *ecp, const char *name);
44a85fe12eSEd Maste static void	insert_sections(struct elfcopy *ecp);
45a85fe12eSEd Maste static void	insert_to_strtab(struct section *t, const char *s);
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 int	lookup_string(struct section *t, const char *s);
53a85fe12eSEd Maste static void	modify_section(struct elfcopy *ecp, struct section *s);
54a85fe12eSEd Maste static void	pad_section(struct elfcopy *ecp, struct section *s);
55a85fe12eSEd Maste static void	print_data(const char *d, size_t sz);
56a85fe12eSEd Maste static void	print_section(struct section *s);
57a85fe12eSEd Maste static void	*read_section(struct section *s, size_t *size);
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
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
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 
122a85fe12eSEd Maste 	is = NULL;
123a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
124a85fe12eSEd Maste 		if (sh_info == elf_ndxscn(is)) {
125a85fe12eSEd Maste 			if (gelf_getshdr(is, &ish) == NULL)
126a85fe12eSEd Maste 				errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
127a85fe12eSEd Maste 				    elf_errmsg(-1));
128a85fe12eSEd Maste 			if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) ==
129a85fe12eSEd Maste 			    NULL)
130a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_strptr failed: %s",
131a85fe12eSEd Maste 				    elf_errmsg(-1));
132a85fe12eSEd Maste 			if (is_remove_section(ecp, name))
133a85fe12eSEd Maste 				return (1);
134a85fe12eSEd Maste 			else
135a85fe12eSEd Maste 				return (0);
136a85fe12eSEd Maste 		}
137a85fe12eSEd Maste 	}
138a85fe12eSEd Maste 	elferr = elf_errno();
139a85fe12eSEd Maste 	if (elferr != 0)
140a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
141a85fe12eSEd Maste 		    elf_errmsg(elferr));
142a85fe12eSEd Maste 
143a85fe12eSEd Maste 	/* Remove reloc section if we can't find the target section. */
144a85fe12eSEd Maste 	return (1);
145a85fe12eSEd Maste }
146a85fe12eSEd Maste 
147a85fe12eSEd Maste static int
148a85fe12eSEd Maste is_append_section(struct elfcopy *ecp, const char *name)
149a85fe12eSEd Maste {
150a85fe12eSEd Maste 	struct sec_action *sac;
151a85fe12eSEd Maste 
152a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
153a85fe12eSEd Maste 	if (sac != NULL && sac->append != 0 && sac->string != NULL)
154a85fe12eSEd Maste 		return (1);
155a85fe12eSEd Maste 
156a85fe12eSEd Maste 	return (0);
157a85fe12eSEd Maste }
158a85fe12eSEd Maste 
159a85fe12eSEd Maste static int
160a85fe12eSEd Maste is_compress_section(struct elfcopy *ecp, const char *name)
161a85fe12eSEd Maste {
162a85fe12eSEd Maste 	struct sec_action *sac;
163a85fe12eSEd Maste 
164a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
165a85fe12eSEd Maste 	if (sac != NULL && sac->compress != 0)
166a85fe12eSEd Maste 		return (1);
167a85fe12eSEd Maste 
168a85fe12eSEd Maste 	return (0);
169a85fe12eSEd Maste }
170a85fe12eSEd Maste 
171a85fe12eSEd Maste static void
172a85fe12eSEd Maste check_section_rename(struct elfcopy *ecp, struct section *s)
173a85fe12eSEd Maste {
174a85fe12eSEd Maste 	struct sec_action *sac;
175a85fe12eSEd Maste 	char *prefix;
176a85fe12eSEd Maste 	size_t namelen;
177a85fe12eSEd Maste 
178a85fe12eSEd Maste 	if (s->pseudo)
179a85fe12eSEd Maste 		return;
180a85fe12eSEd Maste 
181a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, s->name, 0);
182a85fe12eSEd Maste 	if (sac != NULL && sac->rename)
183a85fe12eSEd Maste 		s->name = sac->newname;
184a85fe12eSEd Maste 
185a85fe12eSEd Maste 	if (!strcmp(s->name, ".symtab") ||
186a85fe12eSEd Maste 	    !strcmp(s->name, ".strtab") ||
187a85fe12eSEd Maste 	    !strcmp(s->name, ".shstrtab"))
188a85fe12eSEd Maste 		return;
189a85fe12eSEd Maste 
190a85fe12eSEd Maste 	prefix = NULL;
191a85fe12eSEd Maste 	if (s->loadable && ecp->prefix_alloc != NULL)
192a85fe12eSEd Maste 		prefix = ecp->prefix_alloc;
193a85fe12eSEd Maste 	else if (ecp->prefix_sec != NULL)
194a85fe12eSEd Maste 		prefix = ecp->prefix_sec;
195a85fe12eSEd Maste 
196a85fe12eSEd Maste 	if (prefix != NULL) {
197a85fe12eSEd Maste 		namelen = strlen(s->name) + strlen(prefix) + 1;
198a85fe12eSEd Maste 		if ((s->newname = malloc(namelen)) == NULL)
199a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
200a85fe12eSEd Maste 		snprintf(s->newname, namelen, "%s%s", prefix, s->name);
201a85fe12eSEd Maste 		s->name = s->newname;
202a85fe12eSEd Maste 	}
203a85fe12eSEd Maste }
204a85fe12eSEd Maste 
205a85fe12eSEd Maste static int
206a85fe12eSEd Maste get_section_flags(struct elfcopy *ecp, const char *name)
207a85fe12eSEd Maste {
208a85fe12eSEd Maste 	struct sec_action *sac;
209a85fe12eSEd Maste 
210a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
211a85fe12eSEd Maste 	if (sac != NULL && sac->flags)
212a85fe12eSEd Maste 		return sac->flags;
213a85fe12eSEd Maste 
214a85fe12eSEd Maste 	return (0);
215a85fe12eSEd Maste }
216a85fe12eSEd Maste 
217a85fe12eSEd Maste /*
218a85fe12eSEd Maste  * Determine whether the section are debugging section.
219a85fe12eSEd Maste  * According to libbfd, debugging sections are recognized
220a85fe12eSEd Maste  * only by name.
221a85fe12eSEd Maste  */
222a85fe12eSEd Maste static int
223a85fe12eSEd Maste is_debug_section(const char *name)
224a85fe12eSEd Maste {
225a85fe12eSEd Maste 	const char *dbg_sec[] = {
226839529caSEd Maste 		".apple_",
227a85fe12eSEd Maste 		".debug",
228a85fe12eSEd Maste 		".gnu.linkonce.wi.",
229a85fe12eSEd Maste 		".line",
230a85fe12eSEd Maste 		".stab",
231a85fe12eSEd Maste 		NULL
232a85fe12eSEd Maste 	};
233a85fe12eSEd Maste 	const char **p;
234a85fe12eSEd Maste 
235a85fe12eSEd Maste 	for(p = dbg_sec; *p; p++) {
236a85fe12eSEd Maste 		if (strncmp(name, *p, strlen(*p)) == 0)
237a85fe12eSEd Maste 			return (1);
238a85fe12eSEd Maste 	}
239a85fe12eSEd Maste 
240a85fe12eSEd Maste 	return (0);
241a85fe12eSEd Maste }
242a85fe12eSEd Maste 
243a85fe12eSEd Maste static int
24467d97fe7SEd Maste is_dwo_section(const char *name)
24567d97fe7SEd Maste {
24667d97fe7SEd Maste 	size_t len;
24767d97fe7SEd Maste 
24867d97fe7SEd Maste 	if ((len = strlen(name)) > 4 && strcmp(name + len - 4, ".dwo") == 0)
24967d97fe7SEd Maste 		return (1);
25067d97fe7SEd Maste 	return (0);
25167d97fe7SEd Maste }
25267d97fe7SEd Maste 
25367d97fe7SEd Maste static int
254a85fe12eSEd Maste is_print_section(struct elfcopy *ecp, const char *name)
255a85fe12eSEd Maste {
256a85fe12eSEd Maste 	struct sec_action *sac;
257a85fe12eSEd Maste 
258a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
259a85fe12eSEd Maste 	if (sac != NULL && sac->print != 0)
260a85fe12eSEd Maste 		return (1);
261a85fe12eSEd Maste 
262a85fe12eSEd Maste 	return (0);
263a85fe12eSEd Maste }
264a85fe12eSEd Maste 
265a85fe12eSEd Maste static int
266a85fe12eSEd Maste is_modify_section(struct elfcopy *ecp, const char *name)
267a85fe12eSEd Maste {
268a85fe12eSEd Maste 
269a85fe12eSEd Maste 	if (is_append_section(ecp, name) ||
270a85fe12eSEd Maste 	    is_compress_section(ecp, name))
271a85fe12eSEd Maste 		return (1);
272a85fe12eSEd Maste 
273a85fe12eSEd Maste 	return (0);
274a85fe12eSEd Maste }
275a85fe12eSEd Maste 
276a85fe12eSEd Maste struct sec_action*
277a85fe12eSEd Maste lookup_sec_act(struct elfcopy *ecp, const char *name, int add)
278a85fe12eSEd Maste {
279a85fe12eSEd Maste 	struct sec_action *sac;
280a85fe12eSEd Maste 
281a85fe12eSEd Maste 	if (name == NULL)
282a85fe12eSEd Maste 		return NULL;
283a85fe12eSEd Maste 
284a85fe12eSEd Maste 	STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
285a85fe12eSEd Maste 		if (strcmp(name, sac->name) == 0)
286a85fe12eSEd Maste 			return sac;
287a85fe12eSEd Maste 	}
288a85fe12eSEd Maste 
289a85fe12eSEd Maste 	if (add == 0)
290a85fe12eSEd Maste 		return NULL;
291a85fe12eSEd Maste 
292a85fe12eSEd Maste 	if ((sac = malloc(sizeof(*sac))) == NULL)
293a85fe12eSEd Maste 		errx(EXIT_FAILURE, "not enough memory");
294a85fe12eSEd Maste 	memset(sac, 0, sizeof(*sac));
295a85fe12eSEd Maste 	sac->name = name;
296a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list);
297a85fe12eSEd Maste 
298a85fe12eSEd Maste 	return (sac);
299a85fe12eSEd Maste }
300a85fe12eSEd Maste 
301a85fe12eSEd Maste void
302a85fe12eSEd Maste free_sec_act(struct elfcopy *ecp)
303a85fe12eSEd Maste {
304a85fe12eSEd Maste 	struct sec_action *sac, *sac_temp;
305a85fe12eSEd Maste 
306a85fe12eSEd Maste 	STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) {
307a85fe12eSEd Maste 		STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list);
308a85fe12eSEd Maste 		free(sac);
309a85fe12eSEd Maste 	}
310a85fe12eSEd Maste }
311a85fe12eSEd Maste 
312a85fe12eSEd Maste void
313a85fe12eSEd Maste insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail)
314a85fe12eSEd Maste {
315a85fe12eSEd Maste 	struct section *s;
316a85fe12eSEd Maste 
317a85fe12eSEd Maste 	if (!tail) {
318a85fe12eSEd Maste 		TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
319a85fe12eSEd Maste 			if (sec->off < s->off) {
320a85fe12eSEd Maste 				TAILQ_INSERT_BEFORE(s, sec, sec_list);
321a85fe12eSEd Maste 				goto inc_nos;
322a85fe12eSEd Maste 			}
323a85fe12eSEd Maste 		}
324a85fe12eSEd Maste 	}
325a85fe12eSEd Maste 
326a85fe12eSEd Maste 	TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list);
327a85fe12eSEd Maste 
328a85fe12eSEd Maste inc_nos:
329a85fe12eSEd Maste 	if (sec->pseudo == 0)
330a85fe12eSEd Maste 		ecp->nos++;
331a85fe12eSEd Maste }
332a85fe12eSEd Maste 
333a85fe12eSEd Maste /*
334a85fe12eSEd Maste  * First step of section creation: create scn and internal section
335a85fe12eSEd Maste  * structure, discard sections to be removed.
336a85fe12eSEd Maste  */
337a85fe12eSEd Maste void
338a85fe12eSEd Maste create_scn(struct elfcopy *ecp)
339a85fe12eSEd Maste {
340a85fe12eSEd Maste 	struct section	*s;
341a85fe12eSEd Maste 	const char	*name;
342a85fe12eSEd Maste 	Elf_Scn		*is;
343a85fe12eSEd Maste 	GElf_Shdr	 ish;
344a85fe12eSEd Maste 	size_t		 indx;
345a85fe12eSEd Maste 	uint64_t	 oldndx, newndx;
346d938d64eSEd Maste 	int		 elferr, sec_flags, reorder;
347a85fe12eSEd Maste 
348a85fe12eSEd Maste 	/*
349a85fe12eSEd Maste 	 * Insert a pseudo section that contains the ELF header
350a85fe12eSEd Maste 	 * and program header. Used as reference for section offset
351a85fe12eSEd Maste 	 * or load address adjustment.
352a85fe12eSEd Maste 	 */
353a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
354a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
355a85fe12eSEd Maste 	s->off = 0;
356a85fe12eSEd Maste 	s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) +
357a85fe12eSEd Maste 	    gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT);
358a85fe12eSEd Maste 	s->align = 1;
359a85fe12eSEd Maste 	s->pseudo = 1;
360a85fe12eSEd Maste 	s->loadable = add_to_inseg_list(ecp, s);
361a85fe12eSEd Maste 	insert_to_sec_list(ecp, s, 0);
362a85fe12eSEd Maste 
363a85fe12eSEd Maste 	/* Create internal .shstrtab section. */
364a85fe12eSEd Maste 	init_shstrtab(ecp);
365a85fe12eSEd Maste 
366a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
367a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
368a85fe12eSEd Maste 		    elf_errmsg(-1));
369a85fe12eSEd Maste 
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) {
444a85fe12eSEd Maste 			if (!strcmp(name, ".shstrtab")) {
445a85fe12eSEd Maste 				/*
446a85fe12eSEd Maste 				 * Add sections specified by --add-section and
447a85fe12eSEd Maste 				 * gnu debuglink. we want these sections have
448a85fe12eSEd Maste 				 * smaller index than .shstrtab section.
449a85fe12eSEd Maste 				 */
450a85fe12eSEd Maste 				if (ecp->debuglink != NULL)
451a85fe12eSEd Maste 					add_gnu_debuglink(ecp);
452a85fe12eSEd Maste 				if (ecp->flags & SEC_ADD)
453a85fe12eSEd Maste 					insert_sections(ecp);
454a85fe12eSEd Maste 			}
455a85fe12eSEd Maste  			if ((s->os = elf_newscn(ecp->eout)) == NULL)
456a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_newscn failed: %s",
457a85fe12eSEd Maste 				    elf_errmsg(-1));
458a85fe12eSEd Maste 			if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF)
459a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
460a85fe12eSEd Maste 				    elf_errmsg(-1));
461a85fe12eSEd Maste 		}
462a85fe12eSEd Maste 		if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF)
463a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
464a85fe12eSEd Maste 			    elf_errmsg(-1));
465a85fe12eSEd Maste 		if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF)
466a85fe12eSEd Maste 			ecp->secndx[oldndx] = newndx;
467a85fe12eSEd Maste 
468a85fe12eSEd Maste 		/*
469a85fe12eSEd Maste 		 * If strip action is STRIP_NONDEBUG(only keep debug),
47095fd7f26SEd Maste 		 * change sections type of loadable sections and section
47195fd7f26SEd Maste 		 * groups to SHT_NOBITS, and the content of those sections
47295fd7f26SEd Maste 		 * will be discarded. However, SHT_NOTE sections should
47395fd7f26SEd Maste 		 * be kept.
474a85fe12eSEd Maste 		 */
47595fd7f26SEd Maste 		if (ecp->strip == STRIP_NONDEBUG) {
47695fd7f26SEd Maste 			if (((ish.sh_flags & SHF_ALLOC) ||
47795fd7f26SEd Maste 			    (ish.sh_flags & SHF_GROUP)) &&
47895fd7f26SEd Maste 			    ish.sh_type != SHT_NOTE)
479a85fe12eSEd Maste 				s->type = SHT_NOBITS;
48095fd7f26SEd Maste 		}
481a85fe12eSEd Maste 
482a85fe12eSEd Maste 		check_section_rename(ecp, s);
483a85fe12eSEd Maste 
484a85fe12eSEd Maste 		/* create section header based on input object. */
485a85fe12eSEd Maste 		if (strcmp(name, ".symtab") != 0 &&
486a85fe12eSEd Maste 		    strcmp(name, ".strtab") != 0 &&
487d938d64eSEd Maste 		    strcmp(name, ".shstrtab") != 0) {
488a85fe12eSEd Maste 			copy_shdr(ecp, s, NULL, 0, sec_flags);
489d938d64eSEd Maste 			/*
490d938d64eSEd Maste 			 * elfcopy puts .symtab, .strtab and .shstrtab
491d938d64eSEd Maste 			 * sections in the end of the output object.
492d938d64eSEd Maste 			 * If the input objects have more sections
493d938d64eSEd Maste 			 * after any of these 3 sections, the section
494d938d64eSEd Maste 			 * table will be reordered. section symbols
495d938d64eSEd Maste 			 * should be regenerated for relocations.
496d938d64eSEd Maste 			 */
497d938d64eSEd Maste 			if (reorder)
498d938d64eSEd Maste 				ecp->flags &= ~SYMTAB_INTACT;
499d938d64eSEd Maste 		} else
500d938d64eSEd Maste 			reorder = 1;
501a85fe12eSEd Maste 
502a85fe12eSEd Maste 		if (strcmp(name, ".symtab") == 0) {
503a85fe12eSEd Maste 			ecp->flags |= SYMTAB_EXIST;
504a85fe12eSEd Maste 			ecp->symtab = s;
505a85fe12eSEd Maste 		}
506a85fe12eSEd Maste 		if (strcmp(name, ".strtab") == 0)
507a85fe12eSEd Maste 			ecp->strtab = s;
508a85fe12eSEd Maste 
509a85fe12eSEd Maste 		insert_to_sec_list(ecp, s, 0);
510a85fe12eSEd Maste 	}
511a85fe12eSEd Maste 	elferr = elf_errno();
512a85fe12eSEd Maste 	if (elferr != 0)
513a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
514a85fe12eSEd Maste 		    elf_errmsg(elferr));
515a85fe12eSEd Maste }
516a85fe12eSEd Maste 
517a85fe12eSEd Maste struct section *
518a85fe12eSEd Maste insert_shtab(struct elfcopy *ecp, int tail)
519a85fe12eSEd Maste {
520a85fe12eSEd Maste 	struct section	*s, *shtab;
521a85fe12eSEd Maste 	GElf_Ehdr	 ieh;
522a85fe12eSEd Maste 	int		 nsecs;
523a85fe12eSEd Maste 
524a85fe12eSEd Maste 	/*
525a85fe12eSEd Maste 	 * Treat section header table as a "pseudo" section, insert it
526a85fe12eSEd Maste 	 * into section list, so later it will get sorted and resynced
527a85fe12eSEd Maste 	 * just as normal sections.
528a85fe12eSEd Maste 	 */
529a85fe12eSEd Maste 	if ((shtab = calloc(1, sizeof(*shtab))) == NULL)
530a85fe12eSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
531a85fe12eSEd Maste 	if (!tail) {
5324a85c691SEd Maste 		/*
5334a85c691SEd Maste 		 * "shoff" of input object is used as a hint for section
5344a85c691SEd Maste 		 * resync later.
5354a85c691SEd Maste 		 */
536a85fe12eSEd Maste 		if (gelf_getehdr(ecp->ein, &ieh) == NULL)
537a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
538a85fe12eSEd Maste 			    elf_errmsg(-1));
539a85fe12eSEd Maste 		shtab->off = ieh.e_shoff;
540a85fe12eSEd Maste 	} else
541a85fe12eSEd Maste 		shtab->off = 0;
542a85fe12eSEd Maste 	/* Calculate number of sections in the output object. */
543a85fe12eSEd Maste 	nsecs = 0;
544a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
545a85fe12eSEd Maste 		if (!s->pseudo)
546a85fe12eSEd Maste 			nsecs++;
547a85fe12eSEd Maste 	}
548a85fe12eSEd Maste 	/* Remember there is always a null section, so we +1 here. */
549a85fe12eSEd Maste 	shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT);
550a85fe12eSEd Maste 	if (shtab->sz == 0)
551a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
552a85fe12eSEd Maste 	shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8);
553a85fe12eSEd Maste 	shtab->loadable = 0;
554a85fe12eSEd Maste 	shtab->pseudo = 1;
555a85fe12eSEd Maste 	insert_to_sec_list(ecp, shtab, tail);
556a85fe12eSEd Maste 
557a85fe12eSEd Maste 	return (shtab);
558a85fe12eSEd Maste }
559a85fe12eSEd Maste 
560a85fe12eSEd Maste void
561a85fe12eSEd Maste copy_content(struct elfcopy *ecp)
562a85fe12eSEd Maste {
563a85fe12eSEd Maste 	struct section *s;
564a85fe12eSEd Maste 
565a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
566a85fe12eSEd Maste 		/* Skip pseudo section. */
567a85fe12eSEd Maste 		if (s->pseudo)
568a85fe12eSEd Maste 			continue;
569a85fe12eSEd Maste 
570a85fe12eSEd Maste 		/* Skip special sections. */
571a85fe12eSEd Maste 		if (strcmp(s->name, ".symtab") == 0 ||
572a85fe12eSEd Maste 		    strcmp(s->name, ".strtab") == 0 ||
573a85fe12eSEd Maste 		    strcmp(s->name, ".shstrtab") == 0)
574a85fe12eSEd Maste 			continue;
575a85fe12eSEd Maste 
576a85fe12eSEd Maste 		/*
577*aee4c74cSEd Maste 		 * If strip action is STRIP_ALL, relocation info need
578*aee4c74cSEd Maste 		 * to be stripped. Skip filtering otherwisw.
579*aee4c74cSEd Maste 		 */
580*aee4c74cSEd Maste 		if (ecp->strip == STRIP_ALL &&
581*aee4c74cSEd Maste 		    (s->type == SHT_REL || s->type == SHT_RELA))
582*aee4c74cSEd Maste 			filter_reloc(ecp, s);
583*aee4c74cSEd Maste 
584*aee4c74cSEd Maste 		/*
5853ef90571SEd Maste 		 * The section indices in the SHT_GROUP section needs
5863ef90571SEd Maste 		 * to be updated since we might have stripped some
5873ef90571SEd Maste 		 * sections and changed section numbering.
5883ef90571SEd Maste 		 */
5893ef90571SEd Maste 		if (s->type == SHT_GROUP)
5903ef90571SEd Maste 			update_section_group(ecp, s);
5913ef90571SEd Maste 
592a85fe12eSEd Maste 		if (is_modify_section(ecp, s->name))
593a85fe12eSEd Maste 			modify_section(ecp, s);
594a85fe12eSEd Maste 
595a85fe12eSEd Maste 		copy_data(s);
596a85fe12eSEd Maste 
597a85fe12eSEd Maste 		/*
598a85fe12eSEd Maste 		 * If symbol table is modified, relocation info might
599a85fe12eSEd Maste 		 * need update, as symbol index may have changed.
600a85fe12eSEd Maste 		 */
601a85fe12eSEd Maste 		if ((ecp->flags & SYMTAB_INTACT) == 0 &&
602a85fe12eSEd Maste 		    (ecp->flags & SYMTAB_EXIST) &&
603a85fe12eSEd Maste 		    (s->type == SHT_REL || s->type == SHT_RELA))
604a85fe12eSEd Maste 			update_reloc(ecp, s);
605a85fe12eSEd Maste 
606a85fe12eSEd Maste 		if (is_print_section(ecp, s->name))
607a85fe12eSEd Maste 			print_section(s);
608a85fe12eSEd Maste 	}
609a85fe12eSEd Maste }
610a85fe12eSEd Maste 
6113ef90571SEd Maste 
6123ef90571SEd Maste /*
6133ef90571SEd Maste  * Update section group section. The section indices in the SHT_GROUP
6143ef90571SEd Maste  * section need update after section numbering changed.
6153ef90571SEd Maste  */
6163ef90571SEd Maste static void
6173ef90571SEd Maste update_section_group(struct elfcopy *ecp, struct section *s)
6183ef90571SEd Maste {
6193ef90571SEd Maste 	GElf_Shdr	 ish;
6203ef90571SEd Maste 	Elf_Data	*id;
6213ef90571SEd Maste 	uint32_t	*ws, *wd;
6223ef90571SEd Maste 	uint64_t	 n;
6233ef90571SEd Maste 	size_t		 ishnum;
6243ef90571SEd Maste 	int		 i, j;
6253ef90571SEd Maste 
6263ef90571SEd Maste 	if (!elf_getshnum(ecp->ein, &ishnum))
6273ef90571SEd Maste 		errx(EXIT_FAILURE, "elf_getshnum failed: %s",
6283ef90571SEd Maste 		    elf_errmsg(-1));
6293ef90571SEd Maste 
6303ef90571SEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
6313ef90571SEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
6323ef90571SEd Maste 		    elf_errmsg(-1));
6333ef90571SEd Maste 
6343ef90571SEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL)
6353ef90571SEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
6363ef90571SEd Maste 		    elf_errmsg(-1));
6373ef90571SEd Maste 
6383ef90571SEd Maste 	if (ish.sh_size == 0)
6393ef90571SEd Maste 		return;
6403ef90571SEd Maste 
6413ef90571SEd Maste 	if (ish.sh_entsize == 0)
6423ef90571SEd Maste 		ish.sh_entsize = 4;
6433ef90571SEd Maste 
6443ef90571SEd Maste 	ws = id->d_buf;
6453ef90571SEd Maste 
6463ef90571SEd Maste 	/* We only support COMDAT section. */
6473ef90571SEd Maste #ifndef GRP_COMDAT
6483ef90571SEd Maste #define	GRP_COMDAT 0x1
6493ef90571SEd Maste #endif
6503ef90571SEd Maste 	if ((*ws & GRP_COMDAT) == 0)
6513ef90571SEd Maste 		return;
6523ef90571SEd Maste 
6533ef90571SEd Maste 	if ((s->buf = malloc(ish.sh_size)) == NULL)
6543ef90571SEd Maste 		err(EXIT_FAILURE, "malloc failed");
6553ef90571SEd Maste 
6563ef90571SEd Maste 	s->sz = ish.sh_size;
6573ef90571SEd Maste 
6583ef90571SEd Maste 	wd = s->buf;
6593ef90571SEd Maste 
6603ef90571SEd Maste 	/* Copy the flag word as-is. */
6613ef90571SEd Maste 	*wd = *ws;
6623ef90571SEd Maste 
6633ef90571SEd Maste 	/* Update the section indices. */
6643ef90571SEd Maste 	n = ish.sh_size / ish.sh_entsize;
6653ef90571SEd Maste 	for(i = 1, j = 1; (uint64_t)i < n; i++) {
6663ef90571SEd Maste 		if (ws[i] != SHN_UNDEF && ws[i] < ishnum &&
6673ef90571SEd Maste 		    ecp->secndx[ws[i]] != 0)
6683ef90571SEd Maste 			wd[j++] = ecp->secndx[ws[i]];
6693ef90571SEd Maste 		else
6703ef90571SEd Maste 			s->sz -= 4;
6713ef90571SEd Maste 	}
6723ef90571SEd Maste 
6733ef90571SEd Maste 	s->nocopy = 1;
6743ef90571SEd Maste }
6753ef90571SEd Maste 
676*aee4c74cSEd Maste /*
677*aee4c74cSEd Maste  * Filter relocation entries, only keep those entries whose
678*aee4c74cSEd Maste  * symbol is in the keep list.
679*aee4c74cSEd Maste  */
680*aee4c74cSEd Maste static void
681*aee4c74cSEd Maste filter_reloc(struct elfcopy *ecp, struct section *s)
682*aee4c74cSEd Maste {
683*aee4c74cSEd Maste 	const char	*name;
684*aee4c74cSEd Maste 	GElf_Shdr	 ish;
685*aee4c74cSEd Maste 	GElf_Rel	 rel;
686*aee4c74cSEd Maste 	GElf_Rela	 rela;
687*aee4c74cSEd Maste 	Elf32_Rel	*rel32;
688*aee4c74cSEd Maste 	Elf64_Rel	*rel64;
689*aee4c74cSEd Maste 	Elf32_Rela	*rela32;
690*aee4c74cSEd Maste 	Elf64_Rela	*rela64;
691*aee4c74cSEd Maste 	Elf_Data	*id;
692*aee4c74cSEd Maste 	uint64_t	 cap, n, nrels, sym;
693*aee4c74cSEd Maste 	int		 elferr, i;
694*aee4c74cSEd Maste 
695*aee4c74cSEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
696*aee4c74cSEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
697*aee4c74cSEd Maste 		    elf_errmsg(-1));
698*aee4c74cSEd Maste 
699*aee4c74cSEd Maste 	/* We don't want to touch relocation info for dynamic symbols. */
700*aee4c74cSEd Maste 	if ((ecp->flags & SYMTAB_EXIST) == 0) {
701*aee4c74cSEd Maste 		/*
702*aee4c74cSEd Maste 		 * No symbol table in output.  If sh_link points to a section
703*aee4c74cSEd Maste 		 * that exists in the output object, this relocation section
704*aee4c74cSEd Maste 		 * is for dynamic symbols.  Don't touch it.
705*aee4c74cSEd Maste 		 */
706*aee4c74cSEd Maste 		if (ish.sh_link != 0 && ecp->secndx[ish.sh_link] != 0)
707*aee4c74cSEd Maste 			return;
708*aee4c74cSEd Maste 	} else {
709*aee4c74cSEd Maste 		/* Symbol table exist, check if index equals. */
710*aee4c74cSEd Maste 		if (ish.sh_link != elf_ndxscn(ecp->symtab->is))
711*aee4c74cSEd Maste 			return;
712*aee4c74cSEd Maste 	}
713*aee4c74cSEd Maste 
714*aee4c74cSEd Maste #define	COPYREL(REL, SZ) do {					\
715*aee4c74cSEd Maste 	if (nrels == 0) {					\
716*aee4c74cSEd Maste 		if ((REL##SZ = malloc(cap *			\
717*aee4c74cSEd Maste 		    sizeof(*REL##SZ))) == NULL)			\
718*aee4c74cSEd Maste 			err(EXIT_FAILURE, "malloc failed");	\
719*aee4c74cSEd Maste 	}							\
720*aee4c74cSEd Maste 	if (nrels >= cap) {					\
721*aee4c74cSEd Maste 		cap *= 2;					\
722*aee4c74cSEd Maste 		if ((REL##SZ = realloc(REL##SZ, cap *		\
723*aee4c74cSEd Maste 		    sizeof(*REL##SZ))) == NULL)			\
724*aee4c74cSEd Maste 			err(EXIT_FAILURE, "realloc failed");	\
725*aee4c74cSEd Maste 	}							\
726*aee4c74cSEd Maste 	REL##SZ[nrels].r_offset = REL.r_offset;			\
727*aee4c74cSEd Maste 	REL##SZ[nrels].r_info	= REL.r_info;			\
728*aee4c74cSEd Maste 	if (s->type == SHT_RELA)				\
729*aee4c74cSEd Maste 		rela##SZ[nrels].r_addend = rela.r_addend;	\
730*aee4c74cSEd Maste 	nrels++;						\
731*aee4c74cSEd Maste } while (0)
732*aee4c74cSEd Maste 
733*aee4c74cSEd Maste 	nrels = 0;
734*aee4c74cSEd Maste 	cap = 4;		/* keep list is usually small. */
735*aee4c74cSEd Maste 	rel32 = NULL;
736*aee4c74cSEd Maste 	rel64 = NULL;
737*aee4c74cSEd Maste 	rela32 = NULL;
738*aee4c74cSEd Maste 	rela64 = NULL;
739*aee4c74cSEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL)
740*aee4c74cSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
741*aee4c74cSEd Maste 		    elf_errmsg(-1));
742*aee4c74cSEd Maste 	n = ish.sh_size / ish.sh_entsize;
743*aee4c74cSEd Maste 	for(i = 0; (uint64_t)i < n; i++) {
744*aee4c74cSEd Maste 		if (s->type == SHT_REL) {
745*aee4c74cSEd Maste 			if (gelf_getrel(id, i, &rel) != &rel)
746*aee4c74cSEd Maste 				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
747*aee4c74cSEd Maste 				    elf_errmsg(-1));
748*aee4c74cSEd Maste 			sym = GELF_R_SYM(rel.r_info);
749*aee4c74cSEd Maste 		} else {
750*aee4c74cSEd Maste 			if (gelf_getrela(id, i, &rela) != &rela)
751*aee4c74cSEd Maste 				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
752*aee4c74cSEd Maste 				    elf_errmsg(-1));
753*aee4c74cSEd Maste 			sym = GELF_R_SYM(rela.r_info);
754*aee4c74cSEd Maste 		}
755*aee4c74cSEd Maste 		/*
756*aee4c74cSEd Maste 		 * If a relocation references a symbol and we are omitting
757*aee4c74cSEd Maste 		 * either that symbol or the entire symbol table we cannot
758*aee4c74cSEd Maste 		 * produce valid output, and so just omit the relocation.
759*aee4c74cSEd Maste 		 * Broken output like this is generally not useful, but some
760*aee4c74cSEd Maste 		 * uses of elfcopy/strip rely on it - for example, GCC's build
761*aee4c74cSEd Maste 		 * process uses it to check for build reproducibility by
762*aee4c74cSEd Maste 		 * stripping objects and comparing them.
763*aee4c74cSEd Maste 		 *
764*aee4c74cSEd Maste 		 * Relocations that do not reference a symbol are retained.
765*aee4c74cSEd Maste 		 */
766*aee4c74cSEd Maste 		if (sym != 0) {
767*aee4c74cSEd Maste 			if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0)
768*aee4c74cSEd Maste 				continue;
769*aee4c74cSEd Maste 			name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is),
770*aee4c74cSEd Maste 			    sym);
771*aee4c74cSEd Maste 			if (name == NULL)
772*aee4c74cSEd Maste 				errx(EXIT_FAILURE, "elf_strptr failed: %s",
773*aee4c74cSEd Maste 				    elf_errmsg(-1));
774*aee4c74cSEd Maste 			if (lookup_symop_list(ecp, name, SYMOP_KEEP) == NULL)
775*aee4c74cSEd Maste 				continue;
776*aee4c74cSEd Maste 		}
777*aee4c74cSEd Maste 		if (ecp->oec == ELFCLASS32) {
778*aee4c74cSEd Maste 			if (s->type == SHT_REL)
779*aee4c74cSEd Maste 				COPYREL(rel, 32);
780*aee4c74cSEd Maste 			else
781*aee4c74cSEd Maste 				COPYREL(rela, 32);
782*aee4c74cSEd Maste 		} else {
783*aee4c74cSEd Maste 			if (s->type == SHT_REL)
784*aee4c74cSEd Maste 				COPYREL(rel, 64);
785*aee4c74cSEd Maste 			else
786*aee4c74cSEd Maste 				COPYREL(rela, 64);
787*aee4c74cSEd Maste 		}
788*aee4c74cSEd Maste 	}
789*aee4c74cSEd Maste 	elferr = elf_errno();
790*aee4c74cSEd Maste 	if (elferr != 0)
791*aee4c74cSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
792*aee4c74cSEd Maste 		    elf_errmsg(elferr));
793*aee4c74cSEd Maste 
794*aee4c74cSEd Maste 	if (ecp->oec == ELFCLASS32) {
795*aee4c74cSEd Maste 		if (s->type == SHT_REL)
796*aee4c74cSEd Maste 			s->buf = rel32;
797*aee4c74cSEd Maste 		else
798*aee4c74cSEd Maste 			s->buf = rela32;
799*aee4c74cSEd Maste 	} else {
800*aee4c74cSEd Maste 		if (s->type == SHT_REL)
801*aee4c74cSEd Maste 			s->buf = rel64;
802*aee4c74cSEd Maste 		else
803*aee4c74cSEd Maste 			s->buf = rela64;
804*aee4c74cSEd Maste 	}
805*aee4c74cSEd Maste 	s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL :
806*aee4c74cSEd Maste 	    ELF_T_RELA), nrels, EV_CURRENT);
807*aee4c74cSEd Maste 	s->nocopy = 1;
808*aee4c74cSEd Maste }
809*aee4c74cSEd Maste 
810a85fe12eSEd Maste static void
811a85fe12eSEd Maste update_reloc(struct elfcopy *ecp, struct section *s)
812a85fe12eSEd Maste {
813a85fe12eSEd Maste 	GElf_Shdr	 osh;
814a85fe12eSEd Maste 	GElf_Rel	 rel;
815a85fe12eSEd Maste 	GElf_Rela	 rela;
816a85fe12eSEd Maste 	Elf_Data	*od;
817a85fe12eSEd Maste 	uint64_t	 n;
818a85fe12eSEd Maste 	int		 i;
819a85fe12eSEd Maste 
820a85fe12eSEd Maste #define UPDATEREL(REL) do {						\
821a85fe12eSEd Maste 	if (gelf_get##REL(od, i, &REL) != &REL)				\
822a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_get##REL failed: %s",		\
823a85fe12eSEd Maste 		    elf_errmsg(-1));					\
824a85fe12eSEd Maste 	REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)],	\
825a85fe12eSEd Maste 	    GELF_R_TYPE(REL.r_info));					\
826a85fe12eSEd Maste 	if (!gelf_update_##REL(od, i, &REL))				\
827a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_##REL failed: %s",	\
828a85fe12eSEd Maste 		    elf_errmsg(-1));					\
829a85fe12eSEd Maste } while(0)
830a85fe12eSEd Maste 
831a85fe12eSEd Maste 	if (s->sz == 0)
832a85fe12eSEd Maste 		return;
833a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
834a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
835a85fe12eSEd Maste 		    elf_errmsg(-1));
836a85fe12eSEd Maste 	/* Only process .symtab reloc info. */
837a85fe12eSEd Maste 	if (osh.sh_link != elf_ndxscn(ecp->symtab->is))
838a85fe12eSEd Maste 		return;
839a85fe12eSEd Maste 	if ((od = elf_getdata(s->os, NULL)) == NULL)
840a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
841a85fe12eSEd Maste 		    elf_errmsg(-1));
842a85fe12eSEd Maste 	n = osh.sh_size / osh.sh_entsize;
843a85fe12eSEd Maste 	for(i = 0; (uint64_t)i < n; i++) {
844a85fe12eSEd Maste 		if (s->type == SHT_REL)
845a85fe12eSEd Maste 			UPDATEREL(rel);
846a85fe12eSEd Maste 		else
847a85fe12eSEd Maste 			UPDATEREL(rela);
848a85fe12eSEd Maste 	}
849a85fe12eSEd Maste }
850a85fe12eSEd Maste 
851a85fe12eSEd Maste static void
852a85fe12eSEd Maste pad_section(struct elfcopy *ecp, struct section *s)
853a85fe12eSEd Maste {
854a85fe12eSEd Maste 	GElf_Shdr	 osh;
855a85fe12eSEd Maste 	Elf_Data	*od;
856a85fe12eSEd Maste 
857a85fe12eSEd Maste 	if (s == NULL || s->pad_sz == 0)
858a85fe12eSEd Maste 		return;
859a85fe12eSEd Maste 
860a85fe12eSEd Maste 	if ((s->pad = malloc(s->pad_sz)) == NULL)
861a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
862a85fe12eSEd Maste 	memset(s->pad, ecp->fill, s->pad_sz);
863a85fe12eSEd Maste 
864a85fe12eSEd Maste 	/* Create a new Elf_Data to contain the padding bytes. */
865a85fe12eSEd Maste 	if ((od = elf_newdata(s->os)) == NULL)
866a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
867a85fe12eSEd Maste 		    elf_errmsg(-1));
868a85fe12eSEd Maste 	od->d_align = 1;
869a85fe12eSEd Maste 	od->d_off = s->sz;
870a85fe12eSEd Maste 	od->d_buf = s->pad;
871a85fe12eSEd Maste 	od->d_type = ELF_T_BYTE;
872a85fe12eSEd Maste 	od->d_size = s->pad_sz;
873a85fe12eSEd Maste 	od->d_version = EV_CURRENT;
874a85fe12eSEd Maste 
875a85fe12eSEd Maste 	/* Update section header. */
876a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
877a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
878a85fe12eSEd Maste 		    elf_errmsg(-1));
879a85fe12eSEd Maste 	osh.sh_size = s->sz + s->pad_sz;
880a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &osh))
881a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
882a85fe12eSEd Maste 		    elf_errmsg(-1));
883a85fe12eSEd Maste }
884a85fe12eSEd Maste 
885a85fe12eSEd Maste void
886a85fe12eSEd Maste resync_sections(struct elfcopy *ecp)
887a85fe12eSEd Maste {
888a85fe12eSEd Maste 	struct section	*s, *ps;
889a85fe12eSEd Maste 	GElf_Shdr	 osh;
890a85fe12eSEd Maste 	uint64_t	 off;
891a85fe12eSEd Maste 	int		 first;
892a85fe12eSEd Maste 
893a85fe12eSEd Maste 	ps = NULL;
894a85fe12eSEd Maste 	first = 1;
895a85fe12eSEd Maste 	off = 0;
896a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
897a85fe12eSEd Maste 		if (first) {
898a85fe12eSEd Maste 			off = s->off;
899a85fe12eSEd Maste 			first = 0;
900a85fe12eSEd Maste 		}
901a85fe12eSEd Maste 
9024a85c691SEd Maste 		/*
9034a85c691SEd Maste 		 * Ignore TLS sections with load address 0 and without
9044a85c691SEd Maste 		 * content. We don't need to adjust their file offset or
9054a85c691SEd Maste 		 * VMA, only the size matters.
9064a85c691SEd Maste 		 */
9074a85c691SEd Maste 		if (s->seg_tls != NULL && s->type == SHT_NOBITS &&
9084a85c691SEd Maste 		    s->off == 0)
9094a85c691SEd Maste 			continue;
9104a85c691SEd Maste 
911a85fe12eSEd Maste 		/* Align section offset. */
9122b39d4f6SEd Maste 		if (s->align == 0)
9132b39d4f6SEd Maste 			s->align = 1;
914a85fe12eSEd Maste 		if (off <= s->off) {
915839529caSEd Maste 			if (!s->loadable || (ecp->flags & RELOCATABLE))
916a85fe12eSEd Maste 				s->off = roundup(off, s->align);
917a85fe12eSEd Maste 		} else {
918839529caSEd Maste 			if (s->loadable && (ecp->flags & RELOCATABLE) == 0)
91917eee522SEd Maste 				warnx("moving loadable section %s, "
92017eee522SEd Maste 				    "is this intentional?", s->name);
921a85fe12eSEd Maste 			s->off = roundup(off, s->align);
922a85fe12eSEd Maste 		}
923a85fe12eSEd Maste 
924a85fe12eSEd Maste 		/* Calculate next section offset. */
925a85fe12eSEd Maste 		off = s->off;
926a85fe12eSEd Maste 		if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL))
927a85fe12eSEd Maste 			off += s->sz;
928a85fe12eSEd Maste 
929a85fe12eSEd Maste 		if (s->pseudo) {
930a85fe12eSEd Maste 			ps = NULL;
931a85fe12eSEd Maste 			continue;
932a85fe12eSEd Maste 		}
933a85fe12eSEd Maste 
934a85fe12eSEd Maste 		/* Count padding bytes added through --pad-to. */
935a85fe12eSEd Maste 		if (s->pad_sz > 0)
936a85fe12eSEd Maste 			off += s->pad_sz;
937a85fe12eSEd Maste 
938a85fe12eSEd Maste 		/* Update section header accordingly. */
939a85fe12eSEd Maste 		if (gelf_getshdr(s->os, &osh) == NULL)
940a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
941a85fe12eSEd Maste 			    elf_errmsg(-1));
942a85fe12eSEd Maste 		osh.sh_addr = s->vma;
943a85fe12eSEd Maste 		osh.sh_offset = s->off;
944a85fe12eSEd Maste 		osh.sh_size = s->sz;
945a85fe12eSEd Maste 		if (!gelf_update_shdr(s->os, &osh))
946a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
947a85fe12eSEd Maste 			    elf_errmsg(-1));
948a85fe12eSEd Maste 
949a85fe12eSEd Maste 		/* Add padding for previous section, if need. */
950a85fe12eSEd Maste 		if (ps != NULL) {
951a85fe12eSEd Maste 			if (ps->pad_sz > 0) {
952a85fe12eSEd Maste 				/* Apply padding added by --pad-to. */
953a85fe12eSEd Maste 				pad_section(ecp, ps);
954a85fe12eSEd Maste 			} else if ((ecp->flags & GAP_FILL) &&
955a85fe12eSEd Maste 			    (ps->off + ps->sz < s->off)) {
956a85fe12eSEd Maste 				/*
957a85fe12eSEd Maste 				 * Fill the gap between sections by padding
958a85fe12eSEd Maste 				 * the section with lower address.
959a85fe12eSEd Maste 				 */
960a85fe12eSEd Maste 				ps->pad_sz = s->off - (ps->off + ps->sz);
961a85fe12eSEd Maste 				pad_section(ecp, ps);
962a85fe12eSEd Maste 			}
963a85fe12eSEd Maste 		}
964a85fe12eSEd Maste 
965a85fe12eSEd Maste 		ps = s;
966a85fe12eSEd Maste 	}
967a85fe12eSEd Maste 
968a85fe12eSEd Maste 	/* Pad the last section, if need. */
969a85fe12eSEd Maste 	if (ps != NULL && ps->pad_sz > 0)
970a85fe12eSEd Maste 		pad_section(ecp, ps);
971a85fe12eSEd Maste }
972a85fe12eSEd Maste 
973a85fe12eSEd Maste static void
974a85fe12eSEd Maste modify_section(struct elfcopy *ecp, struct section *s)
975a85fe12eSEd Maste {
976a85fe12eSEd Maste 	struct sec_action	*sac;
977a85fe12eSEd Maste 	size_t			 srcsz, dstsz, p, len;
978a85fe12eSEd Maste 	char			*b, *c, *d, *src, *end;
979a85fe12eSEd Maste 	int			 dupe;
980a85fe12eSEd Maste 
981a85fe12eSEd Maste 	src = read_section(s, &srcsz);
982a85fe12eSEd Maste 	if (src == NULL || srcsz == 0) {
983a85fe12eSEd Maste 		/* For empty section, we proceed if we need to append. */
984a85fe12eSEd Maste 		if (!is_append_section(ecp, s->name))
985a85fe12eSEd Maste 			return;
986a85fe12eSEd Maste 	}
987a85fe12eSEd Maste 
988a85fe12eSEd Maste 	/* Allocate buffer needed for new section data. */
989a85fe12eSEd Maste 	dstsz = srcsz;
990a85fe12eSEd Maste 	if (is_append_section(ecp, s->name)) {
991a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
992a85fe12eSEd Maste 		dstsz += strlen(sac->string) + 1;
993a85fe12eSEd Maste 	}
994a85fe12eSEd Maste 	if ((b = malloc(dstsz)) == NULL)
995a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
996a85fe12eSEd Maste 	s->buf = b;
997a85fe12eSEd Maste 
998a85fe12eSEd Maste 	/* Compress section. */
999a85fe12eSEd Maste 	p = 0;
1000a85fe12eSEd Maste 	if (is_compress_section(ecp, s->name)) {
1001a85fe12eSEd Maste 		end = src + srcsz;
1002a85fe12eSEd Maste 		for(c = src; c < end;) {
1003a85fe12eSEd Maste 			len = 0;
1004a85fe12eSEd Maste 			while(c + len < end && c[len] != '\0')
1005a85fe12eSEd Maste 				len++;
1006a85fe12eSEd Maste 			if (c + len == end) {
1007a85fe12eSEd Maste 				/* XXX should we warn here? */
1008a85fe12eSEd Maste 				strncpy(&b[p], c, len);
1009a85fe12eSEd Maste 				p += len;
1010a85fe12eSEd Maste 				break;
1011a85fe12eSEd Maste 			}
1012a85fe12eSEd Maste 			dupe = 0;
1013a85fe12eSEd Maste 			for (d = b; d < b + p; ) {
1014a85fe12eSEd Maste 				if (strcmp(d, c) == 0) {
1015a85fe12eSEd Maste 					dupe = 1;
1016a85fe12eSEd Maste 					break;
1017a85fe12eSEd Maste 				}
1018a85fe12eSEd Maste 				d += strlen(d) + 1;
1019a85fe12eSEd Maste 			}
1020a85fe12eSEd Maste 			if (!dupe) {
1021a85fe12eSEd Maste 				strncpy(&b[p], c, len);
1022a85fe12eSEd Maste 				b[p + len] = '\0';
1023a85fe12eSEd Maste 				p += len + 1;
1024a85fe12eSEd Maste 			}
1025a85fe12eSEd Maste 			c += len + 1;
1026a85fe12eSEd Maste 		}
1027a85fe12eSEd Maste 	} else {
1028a85fe12eSEd Maste 		memcpy(b, src, srcsz);
1029a85fe12eSEd Maste 		p += srcsz;
1030a85fe12eSEd Maste 	}
1031a85fe12eSEd Maste 
1032a85fe12eSEd Maste 	/* Append section. */
1033a85fe12eSEd Maste 	if (is_append_section(ecp, s->name)) {
1034a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
1035a85fe12eSEd Maste 		len = strlen(sac->string);
1036a85fe12eSEd Maste 		strncpy(&b[p], sac->string, len);
1037a85fe12eSEd Maste 		b[p + len] = '\0';
1038a85fe12eSEd Maste 		p += len + 1;
1039a85fe12eSEd Maste 	}
1040a85fe12eSEd Maste 
1041a85fe12eSEd Maste 	s->sz = p;
1042a85fe12eSEd Maste 	s->nocopy = 1;
1043a85fe12eSEd Maste }
1044a85fe12eSEd Maste 
1045a85fe12eSEd Maste static void
1046a85fe12eSEd Maste print_data(const char *d, size_t sz)
1047a85fe12eSEd Maste {
1048a85fe12eSEd Maste 	const char *c;
1049a85fe12eSEd Maste 
1050a85fe12eSEd Maste 	for (c = d; c < d + sz; c++) {
1051a85fe12eSEd Maste 		if (*c == '\0')
1052a85fe12eSEd Maste 			putchar('\n');
1053a85fe12eSEd Maste 		else
1054a85fe12eSEd Maste 			putchar(*c);
1055a85fe12eSEd Maste 	}
1056a85fe12eSEd Maste }
1057a85fe12eSEd Maste 
1058a85fe12eSEd Maste static void
1059a85fe12eSEd Maste print_section(struct section *s)
1060a85fe12eSEd Maste {
1061a85fe12eSEd Maste 	Elf_Data	*id;
1062a85fe12eSEd Maste 	int		 elferr;
1063a85fe12eSEd Maste 
1064a85fe12eSEd Maste 	if (s->buf != NULL && s->sz > 0) {
1065a85fe12eSEd Maste 		print_data(s->buf, s->sz);
1066a85fe12eSEd Maste 	} else {
1067a85fe12eSEd Maste 		id = NULL;
1068839529caSEd Maste 		while ((id = elf_getdata(s->is, id)) != NULL ||
1069839529caSEd Maste 		    (id = elf_rawdata(s->is, id)) != NULL) {
1070839529caSEd Maste 			(void) elf_errno();
1071a85fe12eSEd Maste 			print_data(id->d_buf, id->d_size);
1072839529caSEd Maste 		}
1073a85fe12eSEd Maste 		elferr = elf_errno();
1074a85fe12eSEd Maste 		if (elferr != 0)
1075a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1076a85fe12eSEd Maste 			    elf_errmsg(elferr));
1077a85fe12eSEd Maste 	}
1078a85fe12eSEd Maste 	putchar('\n');
1079a85fe12eSEd Maste }
1080a85fe12eSEd Maste 
1081a85fe12eSEd Maste static void *
1082a85fe12eSEd Maste read_section(struct section *s, size_t *size)
1083a85fe12eSEd Maste {
1084a85fe12eSEd Maste 	Elf_Data	*id;
1085a85fe12eSEd Maste 	char		*b;
1086a85fe12eSEd Maste 	size_t		 sz;
1087a85fe12eSEd Maste 	int		 elferr;
1088a85fe12eSEd Maste 
1089a85fe12eSEd Maste 	sz = 0;
1090a85fe12eSEd Maste 	b = NULL;
1091a85fe12eSEd Maste 	id = NULL;
1092839529caSEd Maste 	while ((id = elf_getdata(s->is, id)) != NULL ||
1093839529caSEd Maste 	    (id = elf_rawdata(s->is, id)) != NULL) {
1094839529caSEd Maste 		(void) elf_errno();
1095a85fe12eSEd Maste 		if (b == NULL)
1096a85fe12eSEd Maste 			b = malloc(id->d_size);
1097a85fe12eSEd Maste 		else
1098a85fe12eSEd Maste 			b = malloc(sz + id->d_size);
1099a85fe12eSEd Maste 		if (b == NULL)
1100a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc or realloc failed");
1101a85fe12eSEd Maste 
1102a85fe12eSEd Maste 		memcpy(&b[sz], id->d_buf, id->d_size);
1103a85fe12eSEd Maste 		sz += id->d_size;
1104a85fe12eSEd Maste 	}
1105a85fe12eSEd Maste 	elferr = elf_errno();
1106a85fe12eSEd Maste 	if (elferr != 0)
1107a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1108a85fe12eSEd Maste 		    elf_errmsg(elferr));
1109a85fe12eSEd Maste 
1110a85fe12eSEd Maste 	*size = sz;
1111a85fe12eSEd Maste 
1112a85fe12eSEd Maste 	return (b);
1113a85fe12eSEd Maste }
1114a85fe12eSEd Maste 
1115a85fe12eSEd Maste void
1116a85fe12eSEd Maste copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy,
1117a85fe12eSEd Maste     int sec_flags)
1118a85fe12eSEd Maste {
1119a85fe12eSEd Maste 	GElf_Shdr ish, osh;
1120a85fe12eSEd Maste 
1121a85fe12eSEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
1122839529caSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1123a85fe12eSEd Maste 		    elf_errmsg(-1));
1124a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
1125839529caSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1126a85fe12eSEd Maste 		    elf_errmsg(-1));
1127a85fe12eSEd Maste 
1128a85fe12eSEd Maste 	if (copy)
1129a85fe12eSEd Maste 		(void) memcpy(&osh, &ish, sizeof(ish));
1130a85fe12eSEd Maste 	else {
1131a85fe12eSEd Maste 		osh.sh_type		= s->type;
1132a85fe12eSEd Maste 		osh.sh_addr		= s->vma;
1133a85fe12eSEd Maste 		osh.sh_offset		= s->off;
1134a85fe12eSEd Maste 		osh.sh_size		= s->sz;
1135a85fe12eSEd Maste 		osh.sh_link		= ish.sh_link;
1136a85fe12eSEd Maste 		osh.sh_info		= ish.sh_info;
1137a85fe12eSEd Maste 		osh.sh_addralign	= s->align;
1138a85fe12eSEd Maste 		osh.sh_entsize		= ish.sh_entsize;
1139a85fe12eSEd Maste 
1140a85fe12eSEd Maste 		if (sec_flags) {
1141a85fe12eSEd Maste 			osh.sh_flags = 0;
1142839529caSEd Maste 			if (sec_flags & SF_ALLOC)
1143a85fe12eSEd Maste 				osh.sh_flags |= SHF_ALLOC;
1144a85fe12eSEd Maste 			if ((sec_flags & SF_READONLY) == 0)
1145a85fe12eSEd Maste 				osh.sh_flags |= SHF_WRITE;
1146a85fe12eSEd Maste 			if (sec_flags & SF_CODE)
1147a85fe12eSEd Maste 				osh.sh_flags |= SHF_EXECINSTR;
1148839529caSEd Maste 			if ((sec_flags & SF_CONTENTS) &&
1149839529caSEd Maste 			    s->type == SHT_NOBITS && s->sz > 0) {
1150839529caSEd Maste 				/*
1151839529caSEd Maste 				 * Convert SHT_NOBITS section to section with
1152839529caSEd Maste 				 * (zero'ed) content on file.
1153839529caSEd Maste 				 */
1154839529caSEd Maste 				osh.sh_type = s->type = SHT_PROGBITS;
1155839529caSEd Maste 				if ((s->buf = calloc(1, s->sz)) == NULL)
1156839529caSEd Maste 					err(EXIT_FAILURE, "malloc failed");
1157839529caSEd Maste 				s->nocopy = 1;
1158839529caSEd Maste 			}
11593ef90571SEd Maste 		} else {
1160a85fe12eSEd Maste 			osh.sh_flags = ish.sh_flags;
1161839529caSEd Maste 			/*
1162839529caSEd Maste 			 * Newer binutils as(1) emits the section flag
1163839529caSEd Maste 			 * SHF_INFO_LINK for relocation sections. elfcopy
1164839529caSEd Maste 			 * emits this flag in the output section if it's
1165839529caSEd Maste 			 * missing in the input section, to remain compatible
1166839529caSEd Maste 			 * with binutils.
1167839529caSEd Maste 			 */
11683ef90571SEd Maste 			if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)
11693ef90571SEd Maste 				osh.sh_flags |= SHF_INFO_LINK;
11703ef90571SEd Maste 		}
1171a85fe12eSEd Maste 	}
1172a85fe12eSEd Maste 
1173a85fe12eSEd Maste 	if (name == NULL)
1174a85fe12eSEd Maste 		add_to_shstrtab(ecp, s->name);
1175a85fe12eSEd Maste 	else
1176a85fe12eSEd Maste 		add_to_shstrtab(ecp, name);
1177a85fe12eSEd Maste 
1178a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &osh))
1179a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
1180a85fe12eSEd Maste 		    elf_errmsg(-1));
1181a85fe12eSEd Maste }
1182a85fe12eSEd Maste 
1183a85fe12eSEd Maste void
1184a85fe12eSEd Maste copy_data(struct section *s)
1185a85fe12eSEd Maste {
1186a85fe12eSEd Maste 	Elf_Data	*id, *od;
1187a85fe12eSEd Maste 	int		 elferr;
1188a85fe12eSEd Maste 
1189a85fe12eSEd Maste 	if (s->nocopy && s->buf == NULL)
1190a85fe12eSEd Maste 		return;
1191a85fe12eSEd Maste 
1192a85fe12eSEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL) {
1193839529caSEd Maste 		(void) elf_errno();
1194839529caSEd Maste 		if ((id = elf_rawdata(s->is, NULL)) == NULL) {
1195a85fe12eSEd Maste 			elferr = elf_errno();
1196a85fe12eSEd Maste 			if (elferr != 0)
1197839529caSEd Maste 				errx(EXIT_FAILURE, "failed to read section:"
1198839529caSEd Maste 				    " %s", s->name);
1199a85fe12eSEd Maste 			return;
1200a85fe12eSEd Maste 		}
1201839529caSEd Maste 	}
1202a85fe12eSEd Maste 
1203a85fe12eSEd Maste 	if ((od = elf_newdata(s->os)) == NULL)
1204a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1205a85fe12eSEd Maste 		    elf_errmsg(-1));
1206a85fe12eSEd Maste 
1207a85fe12eSEd Maste 	if (s->nocopy) {
1208a85fe12eSEd Maste 		/* Use s->buf as content if s->nocopy is set. */
1209a85fe12eSEd Maste 		od->d_align	= id->d_align;
1210a85fe12eSEd Maste 		od->d_off	= 0;
1211a85fe12eSEd Maste 		od->d_buf	= s->buf;
1212a85fe12eSEd Maste 		od->d_type	= id->d_type;
1213a85fe12eSEd Maste 		od->d_size	= s->sz;
1214a85fe12eSEd Maste 		od->d_version	= id->d_version;
1215a85fe12eSEd Maste 	} else {
1216a85fe12eSEd Maste 		od->d_align	= id->d_align;
1217a85fe12eSEd Maste 		od->d_off	= id->d_off;
1218a85fe12eSEd Maste 		od->d_buf	= id->d_buf;
1219a85fe12eSEd Maste 		od->d_type	= id->d_type;
1220a85fe12eSEd Maste 		od->d_size	= id->d_size;
1221a85fe12eSEd Maste 		od->d_version	= id->d_version;
1222a85fe12eSEd Maste 	}
12234a85c691SEd Maste 
12244a85c691SEd Maste 	/*
12254a85c691SEd Maste 	 * Alignment Fixup. libelf does not allow the alignment for
12264a85c691SEd Maste 	 * Elf_Data descriptor to be set to 0. In this case we workaround
12274a85c691SEd Maste 	 * it by setting the alignment to 1.
12284a85c691SEd Maste 	 *
12294a85c691SEd Maste 	 * According to the ELF ABI, alignment 0 and 1 has the same
12304a85c691SEd Maste 	 * meaning: the section has no alignment constraints.
12314a85c691SEd Maste 	 */
12324a85c691SEd Maste 	if (od->d_align == 0)
12334a85c691SEd Maste 		od->d_align = 1;
1234a85fe12eSEd Maste }
1235a85fe12eSEd Maste 
1236a85fe12eSEd Maste struct section *
1237a85fe12eSEd Maste create_external_section(struct elfcopy *ecp, const char *name, char *newname,
1238a85fe12eSEd Maste     void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype,
1239a85fe12eSEd Maste     uint64_t flags, uint64_t align, uint64_t vma, int loadable)
1240a85fe12eSEd Maste {
1241a85fe12eSEd Maste 	struct section	*s;
1242a85fe12eSEd Maste 	Elf_Scn		*os;
1243a85fe12eSEd Maste 	Elf_Data	*od;
1244a85fe12eSEd Maste 	GElf_Shdr	 osh;
1245a85fe12eSEd Maste 
1246a85fe12eSEd Maste 	if ((os = elf_newscn(ecp->eout)) == NULL)
1247a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newscn() failed: %s",
1248a85fe12eSEd Maste 		    elf_errmsg(-1));
1249a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
1250a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
1251a85fe12eSEd Maste 	s->name = name;
1252a85fe12eSEd Maste 	s->newname = newname;	/* needs to be free()'ed */
1253a85fe12eSEd Maste 	s->off = off;
1254a85fe12eSEd Maste 	s->sz = size;
1255a85fe12eSEd Maste 	s->vma = vma;
1256a85fe12eSEd Maste 	s->align = align;
1257a85fe12eSEd Maste 	s->loadable = loadable;
1258a85fe12eSEd Maste 	s->is = NULL;
1259a85fe12eSEd Maste 	s->os = os;
1260a85fe12eSEd Maste 	s->type = stype;
1261a85fe12eSEd Maste 	s->nocopy = 1;
1262a85fe12eSEd Maste 	insert_to_sec_list(ecp, s, 1);
1263a85fe12eSEd Maste 
1264a85fe12eSEd Maste 	if (gelf_getshdr(os, &osh) == NULL)
1265a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1266a85fe12eSEd Maste 		    elf_errmsg(-1));
1267a85fe12eSEd Maste 	osh.sh_flags = flags;
1268a85fe12eSEd Maste 	osh.sh_type = s->type;
1269a85fe12eSEd Maste 	osh.sh_addr = s->vma;
1270a85fe12eSEd Maste 	osh.sh_addralign = s->align;
1271a85fe12eSEd Maste 	if (!gelf_update_shdr(os, &osh))
1272a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1273a85fe12eSEd Maste 		    elf_errmsg(-1));
1274a85fe12eSEd Maste 	add_to_shstrtab(ecp, name);
1275a85fe12eSEd Maste 
1276a85fe12eSEd Maste 	if (buf != NULL && size != 0) {
1277a85fe12eSEd Maste 		if ((od = elf_newdata(os)) == NULL)
1278a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1279a85fe12eSEd Maste 			    elf_errmsg(-1));
1280a85fe12eSEd Maste 		od->d_align = align;
1281a85fe12eSEd Maste 		od->d_off = 0;
1282a85fe12eSEd Maste 		od->d_buf = buf;
1283a85fe12eSEd Maste 		od->d_size = size;
1284a85fe12eSEd Maste 		od->d_type = dtype;
1285a85fe12eSEd Maste 		od->d_version = EV_CURRENT;
1286a85fe12eSEd Maste 	}
1287a85fe12eSEd Maste 
1288a85fe12eSEd Maste 	/*
1289a85fe12eSEd Maste 	 * Clear SYMTAB_INTACT, as we probably need to update/add new
1290a85fe12eSEd Maste 	 * STT_SECTION symbols into the symbol table.
1291a85fe12eSEd Maste 	 */
1292a85fe12eSEd Maste 	ecp->flags &= ~SYMTAB_INTACT;
1293a85fe12eSEd Maste 
1294a85fe12eSEd Maste 	return (s);
1295a85fe12eSEd Maste }
1296a85fe12eSEd Maste 
1297a85fe12eSEd Maste /*
1298a85fe12eSEd Maste  * Insert sections specified by --add-section to the end of section list.
1299a85fe12eSEd Maste  */
1300a85fe12eSEd Maste static void
1301a85fe12eSEd Maste insert_sections(struct elfcopy *ecp)
1302a85fe12eSEd Maste {
1303a85fe12eSEd Maste 	struct sec_add	*sa;
1304a85fe12eSEd Maste 	struct section	*s;
1305a85fe12eSEd Maste 	size_t		 off;
1306839529caSEd Maste 	uint64_t	 stype;
1307a85fe12eSEd Maste 
1308a85fe12eSEd Maste 	/* Put these sections in the end of current list. */
1309a85fe12eSEd Maste 	off = 0;
1310a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1311a85fe12eSEd Maste 		if (s->type != SHT_NOBITS && s->type != SHT_NULL)
1312a85fe12eSEd Maste 			off = s->off + s->sz;
1313a85fe12eSEd Maste 		else
1314a85fe12eSEd Maste 			off = s->off;
1315a85fe12eSEd Maste 	}
1316a85fe12eSEd Maste 
1317a85fe12eSEd Maste 	STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) {
1318a85fe12eSEd Maste 
1319a85fe12eSEd Maste 		/* TODO: Add section header vma/lma, flag changes here */
1320a85fe12eSEd Maste 
1321839529caSEd Maste 		/*
1322839529caSEd Maste 		 * The default section type for user added section is
1323839529caSEd Maste 		 * SHT_PROGBITS. If the section name match certain patterns,
1324839529caSEd Maste 		 * elfcopy will try to set a more appropriate section type.
1325839529caSEd Maste 		 * However, data type is always set to ELF_T_BYTE and no
1326839529caSEd Maste 		 * translation is performed by libelf.
1327839529caSEd Maste 		 */
1328839529caSEd Maste 		stype = SHT_PROGBITS;
1329839529caSEd Maste 		if (strcmp(sa->name, ".note") == 0 ||
1330839529caSEd Maste 		    strncmp(sa->name, ".note.", strlen(".note.")) == 0)
1331839529caSEd Maste 			stype = SHT_NOTE;
1332839529caSEd Maste 
1333a85fe12eSEd Maste 		(void) create_external_section(ecp, sa->name, NULL, sa->content,
1334839529caSEd Maste 		    sa->size, off, stype, ELF_T_BYTE, 0, 1, 0, 0);
1335a85fe12eSEd Maste 	}
1336a85fe12eSEd Maste }
1337a85fe12eSEd Maste 
1338a85fe12eSEd Maste void
1339a85fe12eSEd Maste add_to_shstrtab(struct elfcopy *ecp, const char *name)
1340a85fe12eSEd Maste {
1341a85fe12eSEd Maste 	struct section *s;
1342a85fe12eSEd Maste 
1343a85fe12eSEd Maste 	s = ecp->shstrtab;
1344a85fe12eSEd Maste 	insert_to_strtab(s, name);
1345a85fe12eSEd Maste }
1346a85fe12eSEd Maste 
1347a85fe12eSEd Maste void
1348a85fe12eSEd Maste update_shdr(struct elfcopy *ecp, int update_link)
1349a85fe12eSEd Maste {
1350a85fe12eSEd Maste 	struct section	*s;
1351a85fe12eSEd Maste 	GElf_Shdr	 osh;
1352a85fe12eSEd Maste 	int		 elferr;
1353a85fe12eSEd Maste 
1354a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1355a85fe12eSEd Maste 		if (s->pseudo)
1356a85fe12eSEd Maste 			continue;
1357a85fe12eSEd Maste 
1358a85fe12eSEd Maste 		if (gelf_getshdr(s->os, &osh) == NULL)
1359839529caSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
1360a85fe12eSEd Maste 			    elf_errmsg(-1));
1361a85fe12eSEd Maste 
1362a85fe12eSEd Maste 		/* Find section name in string table and set sh_name. */
1363a85fe12eSEd Maste 		osh.sh_name = lookup_string(ecp->shstrtab, s->name);
1364a85fe12eSEd Maste 
1365a85fe12eSEd Maste 		/*
1366a85fe12eSEd Maste 		 * sh_link needs to be updated, since the index of the
1367a85fe12eSEd Maste 		 * linked section might have changed.
1368a85fe12eSEd Maste 		 */
1369a85fe12eSEd Maste 		if (update_link && osh.sh_link != 0)
1370a85fe12eSEd Maste 			osh.sh_link = ecp->secndx[osh.sh_link];
1371a85fe12eSEd Maste 
1372a85fe12eSEd Maste 		/*
1373a85fe12eSEd Maste 		 * sh_info of relocation section links to the section to which
1374a85fe12eSEd Maste 		 * its relocation info applies. So it may need update as well.
1375a85fe12eSEd Maste 		 */
1376a85fe12eSEd Maste 		if ((s->type == SHT_REL || s->type == SHT_RELA) &&
1377a85fe12eSEd Maste 		    osh.sh_info != 0)
1378a85fe12eSEd Maste 			osh.sh_info = ecp->secndx[osh.sh_info];
1379a85fe12eSEd Maste 
1380b00fe64fSEd Maste 		/*
1381b00fe64fSEd Maste 		 * sh_info of SHT_GROUP section needs to point to the correct
1382b00fe64fSEd Maste 		 * string in the symbol table.
1383b00fe64fSEd Maste 		 */
1384b00fe64fSEd Maste 		if (s->type == SHT_GROUP && (ecp->flags & SYMTAB_EXIST) &&
1385b00fe64fSEd Maste 		    (ecp->flags & SYMTAB_INTACT) == 0)
1386b00fe64fSEd Maste 			osh.sh_info = ecp->symndx[osh.sh_info];
1387b00fe64fSEd Maste 
1388a85fe12eSEd Maste 		if (!gelf_update_shdr(s->os, &osh))
1389a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1390a85fe12eSEd Maste 			    elf_errmsg(-1));
1391a85fe12eSEd Maste 	}
1392a85fe12eSEd Maste 	elferr = elf_errno();
1393a85fe12eSEd Maste 	if (elferr != 0)
1394a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
1395a85fe12eSEd Maste 		    elf_errmsg(elferr));
1396a85fe12eSEd Maste }
1397a85fe12eSEd Maste 
1398a85fe12eSEd Maste void
1399a85fe12eSEd Maste init_shstrtab(struct elfcopy *ecp)
1400a85fe12eSEd Maste {
1401a85fe12eSEd Maste 	struct section *s;
1402a85fe12eSEd Maste 
1403a85fe12eSEd Maste 	if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL)
1404a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
1405a85fe12eSEd Maste 	s = ecp->shstrtab;
1406a85fe12eSEd Maste 	s->name = ".shstrtab";
1407a85fe12eSEd Maste 	s->is = NULL;
1408a85fe12eSEd Maste 	s->sz = 0;
1409a85fe12eSEd Maste 	s->align = 1;
1410a85fe12eSEd Maste 	s->loadable = 0;
1411a85fe12eSEd Maste 	s->type = SHT_STRTAB;
1412a85fe12eSEd Maste 	s->vma = 0;
14139ef62fdbSEd Maste 
14149ef62fdbSEd Maste 	insert_to_strtab(s, "");
14159ef62fdbSEd Maste 	insert_to_strtab(s, ".symtab");
14169ef62fdbSEd Maste 	insert_to_strtab(s, ".strtab");
14179ef62fdbSEd Maste 	insert_to_strtab(s, ".shstrtab");
1418a85fe12eSEd Maste }
1419a85fe12eSEd Maste 
1420a85fe12eSEd Maste void
1421a85fe12eSEd Maste set_shstrtab(struct elfcopy *ecp)
1422a85fe12eSEd Maste {
1423a85fe12eSEd Maste 	struct section	*s;
1424a85fe12eSEd Maste 	Elf_Data	*data;
1425a85fe12eSEd Maste 	GElf_Shdr	 sh;
1426a85fe12eSEd Maste 
1427a85fe12eSEd Maste 	s = ecp->shstrtab;
1428a85fe12eSEd Maste 
1429619ba3b4SEd Maste 	if (s->os == NULL) {
1430619ba3b4SEd Maste 		/* Input object does not contain .shstrtab section */
1431619ba3b4SEd Maste 		if ((s->os = elf_newscn(ecp->eout)) == NULL)
1432619ba3b4SEd Maste 			errx(EXIT_FAILURE, "elf_newscn failed: %s",
1433619ba3b4SEd Maste 			    elf_errmsg(-1));
1434619ba3b4SEd Maste 		insert_to_sec_list(ecp, s, 1);
1435619ba3b4SEd Maste 	}
1436619ba3b4SEd Maste 
1437a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &sh) == NULL)
1438839529caSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1439a85fe12eSEd Maste 		    elf_errmsg(-1));
1440a85fe12eSEd Maste 	sh.sh_addr	= 0;
1441a85fe12eSEd Maste 	sh.sh_addralign	= 1;
1442a85fe12eSEd Maste 	sh.sh_offset	= s->off;
1443a85fe12eSEd Maste 	sh.sh_type	= SHT_STRTAB;
1444a85fe12eSEd Maste 	sh.sh_flags	= 0;
1445a85fe12eSEd Maste 	sh.sh_entsize	= 0;
1446a85fe12eSEd Maste 	sh.sh_info	= 0;
1447a85fe12eSEd Maste 	sh.sh_link	= 0;
1448a85fe12eSEd Maste 
1449a85fe12eSEd Maste 	if ((data = elf_newdata(s->os)) == NULL)
1450a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1451a85fe12eSEd Maste 		    elf_errmsg(-1));
1452a85fe12eSEd Maste 
1453a85fe12eSEd Maste 	/*
1454a85fe12eSEd Maste 	 * If we don't have a symbol table, skip those a few bytes
1455a85fe12eSEd Maste 	 * which are reserved for this in the beginning of shstrtab.
1456a85fe12eSEd Maste 	 */
1457a85fe12eSEd Maste 	if (!(ecp->flags & SYMTAB_EXIST)) {
1458a85fe12eSEd Maste 		s->sz -= sizeof(".symtab\0.strtab");
1459a85fe12eSEd Maste 		memmove(s->buf, (char *)s->buf + sizeof(".symtab\0.strtab"),
1460a85fe12eSEd Maste 		    s->sz);
1461a85fe12eSEd Maste 	}
1462a85fe12eSEd Maste 
1463a85fe12eSEd Maste 	sh.sh_size	= s->sz;
1464a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &sh))
1465a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1466a85fe12eSEd Maste 		    elf_errmsg(-1));
1467a85fe12eSEd Maste 
1468a85fe12eSEd Maste 	data->d_align	= 1;
1469a85fe12eSEd Maste 	data->d_buf	= s->buf;
1470a85fe12eSEd Maste 	data->d_size	= s->sz;
1471a85fe12eSEd Maste 	data->d_off	= 0;
1472a85fe12eSEd Maste 	data->d_type	= ELF_T_BYTE;
1473a85fe12eSEd Maste 	data->d_version	= EV_CURRENT;
1474a85fe12eSEd Maste 
1475a85fe12eSEd Maste 	if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os)))
1476a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s",
1477a85fe12eSEd Maste 		     elf_errmsg(-1));
1478a85fe12eSEd Maste }
1479a85fe12eSEd Maste 
1480a85fe12eSEd Maste void
1481a85fe12eSEd Maste add_section(struct elfcopy *ecp, const char *arg)
1482a85fe12eSEd Maste {
1483a85fe12eSEd Maste 	struct sec_add	*sa;
1484a85fe12eSEd Maste 	struct stat	 sb;
1485a85fe12eSEd Maste 	const char	*s, *fn;
1486a85fe12eSEd Maste 	FILE		*fp;
1487a85fe12eSEd Maste 	int		 len;
1488a85fe12eSEd Maste 
1489a85fe12eSEd Maste 	if ((s = strchr(arg, '=')) == NULL)
1490a85fe12eSEd Maste 		errx(EXIT_FAILURE,
1491a85fe12eSEd Maste 		    "illegal format for --add-section option");
1492a85fe12eSEd Maste 	if ((sa = malloc(sizeof(*sa))) == NULL)
1493a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1494a85fe12eSEd Maste 
1495a85fe12eSEd Maste 	len = s - arg;
1496a85fe12eSEd Maste 	if ((sa->name = malloc(len + 1)) == NULL)
1497a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1498a85fe12eSEd Maste 	strncpy(sa->name, arg, len);
1499a85fe12eSEd Maste 	sa->name[len] = '\0';
1500a85fe12eSEd Maste 
1501a85fe12eSEd Maste 	fn = s + 1;
1502a85fe12eSEd Maste 	if (stat(fn, &sb) == -1)
1503a85fe12eSEd Maste 		err(EXIT_FAILURE, "stat failed");
1504a85fe12eSEd Maste 	sa->size = sb.st_size;
1505839529caSEd Maste 	if (sa->size > 0) {
1506a85fe12eSEd Maste 		if ((sa->content = malloc(sa->size)) == NULL)
1507a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
1508a85fe12eSEd Maste 		if ((fp = fopen(fn, "r")) == NULL)
1509a85fe12eSEd Maste 			err(EXIT_FAILURE, "can not open %s", fn);
1510a85fe12eSEd Maste 		if (fread(sa->content, 1, sa->size, fp) == 0 ||
1511a85fe12eSEd Maste 		    ferror(fp))
1512a85fe12eSEd Maste 			err(EXIT_FAILURE, "fread failed");
1513a85fe12eSEd Maste 		fclose(fp);
1514839529caSEd Maste 	} else
1515839529caSEd Maste 		sa->content = NULL;
1516a85fe12eSEd Maste 
1517a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1518a85fe12eSEd Maste 	ecp->flags |= SEC_ADD;
1519a85fe12eSEd Maste }
1520a85fe12eSEd Maste 
1521a85fe12eSEd Maste void
1522a85fe12eSEd Maste free_sec_add(struct elfcopy *ecp)
1523a85fe12eSEd Maste {
1524a85fe12eSEd Maste 	struct sec_add *sa, *sa_temp;
1525a85fe12eSEd Maste 
1526a85fe12eSEd Maste 	STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) {
1527a85fe12eSEd Maste 		STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list);
1528a85fe12eSEd Maste 		free(sa->name);
1529a85fe12eSEd Maste 		free(sa->content);
1530a85fe12eSEd Maste 		free(sa);
1531a85fe12eSEd Maste 	}
1532a85fe12eSEd Maste }
1533a85fe12eSEd Maste 
1534a85fe12eSEd Maste static void
1535a85fe12eSEd Maste add_gnu_debuglink(struct elfcopy *ecp)
1536a85fe12eSEd Maste {
1537a85fe12eSEd Maste 	struct sec_add	*sa;
1538a85fe12eSEd Maste 	struct stat	 sb;
1539a85fe12eSEd Maste 	FILE		*fp;
1540a85fe12eSEd Maste 	char		*fnbase, *buf;
1541a85fe12eSEd Maste 	int		 crc_off;
1542a85fe12eSEd Maste 	int		 crc;
1543a85fe12eSEd Maste 
1544a85fe12eSEd Maste 	if (ecp->debuglink == NULL)
1545a85fe12eSEd Maste 		return;
1546a85fe12eSEd Maste 
1547a85fe12eSEd Maste 	/* Read debug file content. */
1548a85fe12eSEd Maste 	if ((sa = malloc(sizeof(*sa))) == NULL)
1549a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1550a85fe12eSEd Maste 	if ((sa->name = strdup(".gnu_debuglink")) == NULL)
1551a85fe12eSEd Maste 		err(EXIT_FAILURE, "strdup failed");
1552a85fe12eSEd Maste 	if (stat(ecp->debuglink, &sb) == -1)
1553a85fe12eSEd Maste 		err(EXIT_FAILURE, "stat failed");
1554f5e9c916SEd Maste 	if (sb.st_size == 0)
1555f5e9c916SEd Maste 		errx(EXIT_FAILURE, "empty debug link target %s",
1556f5e9c916SEd Maste 		    ecp->debuglink);
1557a85fe12eSEd Maste 	if ((buf = malloc(sb.st_size)) == NULL)
1558a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1559a85fe12eSEd Maste 	if ((fp = fopen(ecp->debuglink, "r")) == NULL)
1560a85fe12eSEd Maste 		err(EXIT_FAILURE, "can not open %s", ecp->debuglink);
1561a85fe12eSEd Maste 	if (fread(buf, 1, sb.st_size, fp) == 0 ||
1562a85fe12eSEd Maste 	    ferror(fp))
1563a85fe12eSEd Maste 		err(EXIT_FAILURE, "fread failed");
1564a85fe12eSEd Maste 	fclose(fp);
1565a85fe12eSEd Maste 
1566a85fe12eSEd Maste 	/* Calculate crc checksum.  */
1567a85fe12eSEd Maste 	crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF);
1568a85fe12eSEd Maste 	free(buf);
1569a85fe12eSEd Maste 
1570a85fe12eSEd Maste 	/* Calculate section size and the offset to store crc checksum. */
1571a85fe12eSEd Maste 	if ((fnbase = basename(ecp->debuglink)) == NULL)
1572a85fe12eSEd Maste 		err(EXIT_FAILURE, "basename failed");
1573a85fe12eSEd Maste 	crc_off = roundup(strlen(fnbase) + 1, 4);
1574a85fe12eSEd Maste 	sa->size = crc_off + 4;
1575a85fe12eSEd Maste 
1576a85fe12eSEd Maste 	/* Section content. */
1577a85fe12eSEd Maste 	if ((sa->content = calloc(1, sa->size)) == NULL)
1578a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1579a85fe12eSEd Maste 	strncpy(sa->content, fnbase, strlen(fnbase));
1580a85fe12eSEd Maste 	if (ecp->oed == ELFDATA2LSB) {
1581a85fe12eSEd Maste 		sa->content[crc_off] = crc & 0xFF;
1582a85fe12eSEd Maste 		sa->content[crc_off + 1] = (crc >> 8) & 0xFF;
1583a85fe12eSEd Maste 		sa->content[crc_off + 2] = (crc >> 16) & 0xFF;
1584a85fe12eSEd Maste 		sa->content[crc_off + 3] = crc >> 24;
1585a85fe12eSEd Maste 	} else {
1586a85fe12eSEd Maste 		sa->content[crc_off] = crc >> 24;
1587a85fe12eSEd Maste 		sa->content[crc_off + 1] = (crc >> 16) & 0xFF;
1588a85fe12eSEd Maste 		sa->content[crc_off + 2] = (crc >> 8) & 0xFF;
1589a85fe12eSEd Maste 		sa->content[crc_off + 3] = crc & 0xFF;
1590a85fe12eSEd Maste 	}
1591a85fe12eSEd Maste 
1592a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1593a85fe12eSEd Maste 	ecp->flags |= SEC_ADD;
1594a85fe12eSEd Maste }
1595a85fe12eSEd Maste 
1596a85fe12eSEd Maste static void
1597a85fe12eSEd Maste insert_to_strtab(struct section *t, const char *s)
1598a85fe12eSEd Maste {
1599a85fe12eSEd Maste 	const char	*r;
1600a85fe12eSEd Maste 	char		*b, *c;
1601a85fe12eSEd Maste 	size_t		 len, slen;
1602a85fe12eSEd Maste 	int		 append;
1603a85fe12eSEd Maste 
1604a85fe12eSEd Maste 	if (t->sz == 0) {
1605a85fe12eSEd Maste 		t->cap = 512;
1606a85fe12eSEd Maste 		if ((t->buf = malloc(t->cap)) == NULL)
1607a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
1608a85fe12eSEd Maste 	}
1609a85fe12eSEd Maste 
1610a85fe12eSEd Maste 	slen = strlen(s);
1611a85fe12eSEd Maste 	append = 0;
1612a85fe12eSEd Maste 	b = t->buf;
1613a85fe12eSEd Maste 	for (c = b; c < b + t->sz;) {
1614a85fe12eSEd Maste 		len = strlen(c);
1615a85fe12eSEd Maste 		if (!append && len >= slen) {
1616a85fe12eSEd Maste 			r = c + (len - slen);
1617a85fe12eSEd Maste 			if (strcmp(r, s) == 0)
1618a85fe12eSEd Maste 				return;
1619a85fe12eSEd Maste 		} else if (len < slen && len != 0) {
1620a85fe12eSEd Maste 			r = s + (slen - len);
1621a85fe12eSEd Maste 			if (strcmp(c, r) == 0) {
1622a85fe12eSEd Maste 				t->sz -= len + 1;
1623a85fe12eSEd Maste 				memmove(c, c + len + 1, t->sz - (c - b));
1624a85fe12eSEd Maste 				append = 1;
1625a85fe12eSEd Maste 				continue;
1626a85fe12eSEd Maste 			}
1627a85fe12eSEd Maste 		}
1628a85fe12eSEd Maste 		c += len + 1;
1629a85fe12eSEd Maste 	}
1630a85fe12eSEd Maste 
1631a85fe12eSEd Maste 	while (t->sz + slen + 1 >= t->cap) {
1632a85fe12eSEd Maste 		t->cap *= 2;
1633a85fe12eSEd Maste 		if ((t->buf = realloc(t->buf, t->cap)) == NULL)
1634a85fe12eSEd Maste 			err(EXIT_FAILURE, "realloc failed");
1635a85fe12eSEd Maste 	}
1636a85fe12eSEd Maste 	b = t->buf;
1637a85fe12eSEd Maste 	strncpy(&b[t->sz], s, slen);
1638a85fe12eSEd Maste 	b[t->sz + slen] = '\0';
1639a85fe12eSEd Maste 	t->sz += slen + 1;
1640a85fe12eSEd Maste }
1641a85fe12eSEd Maste 
1642a85fe12eSEd Maste static int
1643a85fe12eSEd Maste lookup_string(struct section *t, const char *s)
1644a85fe12eSEd Maste {
1645a85fe12eSEd Maste 	const char	*b, *c, *r;
1646a85fe12eSEd Maste 	size_t		 len, slen;
1647a85fe12eSEd Maste 
1648a85fe12eSEd Maste 	slen = strlen(s);
1649a85fe12eSEd Maste 	b = t->buf;
1650a85fe12eSEd Maste 	for (c = b; c < b + t->sz;) {
1651a85fe12eSEd Maste 		len = strlen(c);
1652a85fe12eSEd Maste 		if (len >= slen) {
1653a85fe12eSEd Maste 			r = c + (len - slen);
1654a85fe12eSEd Maste 			if (strcmp(r, s) == 0)
1655a85fe12eSEd Maste 				return (r - b);
1656a85fe12eSEd Maste 		}
1657a85fe12eSEd Maste 		c += len + 1;
1658a85fe12eSEd Maste 	}
1659a85fe12eSEd Maste 
1660a85fe12eSEd Maste 	return (-1);
1661a85fe12eSEd Maste }
1662a85fe12eSEd Maste 
1663a85fe12eSEd Maste static uint32_t crctable[256] =
1664a85fe12eSEd Maste {
1665a85fe12eSEd Maste 	0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
1666a85fe12eSEd Maste 	0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
1667a85fe12eSEd Maste 	0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
1668a85fe12eSEd Maste 	0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
1669a85fe12eSEd Maste 	0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
1670a85fe12eSEd Maste 	0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
1671a85fe12eSEd Maste 	0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
1672a85fe12eSEd Maste 	0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
1673a85fe12eSEd Maste 	0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
1674a85fe12eSEd Maste 	0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
1675a85fe12eSEd Maste 	0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
1676a85fe12eSEd Maste 	0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
1677a85fe12eSEd Maste 	0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
1678a85fe12eSEd Maste 	0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
1679a85fe12eSEd Maste 	0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
1680a85fe12eSEd Maste 	0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
1681a85fe12eSEd Maste 	0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
1682a85fe12eSEd Maste 	0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
1683a85fe12eSEd Maste 	0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
1684a85fe12eSEd Maste 	0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
1685a85fe12eSEd Maste 	0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
1686a85fe12eSEd Maste 	0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
1687a85fe12eSEd Maste 	0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
1688a85fe12eSEd Maste 	0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
1689a85fe12eSEd Maste 	0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
1690a85fe12eSEd Maste 	0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
1691a85fe12eSEd Maste 	0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
1692a85fe12eSEd Maste 	0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
1693a85fe12eSEd Maste 	0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
1694a85fe12eSEd Maste 	0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
1695a85fe12eSEd Maste 	0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
1696a85fe12eSEd Maste 	0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
1697a85fe12eSEd Maste 	0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
1698a85fe12eSEd Maste 	0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
1699a85fe12eSEd Maste 	0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
1700a85fe12eSEd Maste 	0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
1701a85fe12eSEd Maste 	0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
1702a85fe12eSEd Maste 	0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
1703a85fe12eSEd Maste 	0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
1704a85fe12eSEd Maste 	0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
1705a85fe12eSEd Maste 	0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
1706a85fe12eSEd Maste 	0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
1707a85fe12eSEd Maste 	0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
1708a85fe12eSEd Maste 	0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
1709a85fe12eSEd Maste 	0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
1710a85fe12eSEd Maste 	0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
1711a85fe12eSEd Maste 	0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
1712a85fe12eSEd Maste 	0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
1713a85fe12eSEd Maste 	0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
1714a85fe12eSEd Maste 	0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
1715a85fe12eSEd Maste 	0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
1716a85fe12eSEd Maste 	0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
1717a85fe12eSEd Maste 	0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
1718a85fe12eSEd Maste 	0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
1719a85fe12eSEd Maste 	0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
1720a85fe12eSEd Maste 	0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
1721a85fe12eSEd Maste 	0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
1722a85fe12eSEd Maste 	0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
1723a85fe12eSEd Maste 	0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
1724a85fe12eSEd Maste 	0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
1725a85fe12eSEd Maste 	0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
1726a85fe12eSEd Maste 	0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
1727a85fe12eSEd Maste 	0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
1728a85fe12eSEd Maste 	0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
1729a85fe12eSEd Maste };
1730a85fe12eSEd Maste 
1731a85fe12eSEd Maste static uint32_t
1732a85fe12eSEd Maste calc_crc32(const char *p, size_t len, uint32_t crc)
1733a85fe12eSEd Maste {
1734a85fe12eSEd Maste 	uint32_t i;
1735a85fe12eSEd Maste 
1736a85fe12eSEd Maste 	for (i = 0; i < len; i++) {
1737a85fe12eSEd Maste 		crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);
1738a85fe12eSEd Maste 	}
1739a85fe12eSEd Maste 
1740a85fe12eSEd Maste 	return (crc ^ 0xFFFFFFFF);
1741a85fe12eSEd Maste }
1742