xref: /freebsd/contrib/elftoolchain/elfcopy/sections.c (revision f2530c80db7b29b95368fce956b3a778f096b368)
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 
37d003e0d7SEd Maste ELFTC_VCSID("$Id: sections.c 3758 2019-06-28 01:16:50Z emaste $");
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);
42aee4c74cSEd 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 int	is_append_section(struct elfcopy *ecp, const char *name);
46a85fe12eSEd Maste static int	is_compress_section(struct elfcopy *ecp, const char *name);
47a85fe12eSEd Maste static int	is_debug_section(const char *name);
4867d97fe7SEd Maste static int	is_dwo_section(const char *name);
49a85fe12eSEd Maste static int	is_modify_section(struct elfcopy *ecp, const char *name);
50a85fe12eSEd Maste static int	is_print_section(struct elfcopy *ecp, const char *name);
51a85fe12eSEd Maste static void	modify_section(struct elfcopy *ecp, struct section *s);
52a85fe12eSEd Maste static void	pad_section(struct elfcopy *ecp, struct section *s);
53a85fe12eSEd Maste static void	print_data(const char *d, size_t sz);
54a85fe12eSEd Maste static void	print_section(struct section *s);
55a85fe12eSEd Maste static void	*read_section(struct section *s, size_t *size);
56bc589b72SMark Johnston static void	set_shstrtab(struct elfcopy *ecp);
57a85fe12eSEd Maste static void	update_reloc(struct elfcopy *ecp, struct section *s);
583ef90571SEd Maste static void	update_section_group(struct elfcopy *ecp, struct section *s);
59a85fe12eSEd Maste 
60a85fe12eSEd Maste int
61a85fe12eSEd Maste is_remove_section(struct elfcopy *ecp, const char *name)
62a85fe12eSEd Maste {
63a85fe12eSEd Maste 
64a85fe12eSEd Maste 	/* Always keep section name table */
65a85fe12eSEd Maste 	if (strcmp(name, ".shstrtab") == 0)
66a85fe12eSEd Maste 		return 0;
67a85fe12eSEd Maste 	if (strcmp(name, ".symtab") == 0 ||
68a85fe12eSEd Maste 	    strcmp(name, ".strtab") == 0) {
69a85fe12eSEd Maste 		if (ecp->strip == STRIP_ALL && lookup_symop_list(
70a85fe12eSEd Maste 		    ecp, NULL, SYMOP_KEEP) == NULL)
71a85fe12eSEd Maste 			return (1);
72a85fe12eSEd Maste 		else
73a85fe12eSEd Maste 			return (0);
74a85fe12eSEd Maste 	}
75a85fe12eSEd Maste 
7667d97fe7SEd Maste 	if (ecp->strip == STRIP_DWO && is_dwo_section(name))
7767d97fe7SEd Maste 		return (1);
7867d97fe7SEd Maste 	if (ecp->strip == STRIP_NONDWO && !is_dwo_section(name))
7967d97fe7SEd Maste 		return (1);
8067d97fe7SEd Maste 
81a85fe12eSEd Maste 	if (is_debug_section(name)) {
82a85fe12eSEd Maste 		if (ecp->strip == STRIP_ALL ||
83a85fe12eSEd Maste 		    ecp->strip == STRIP_DEBUG ||
84a85fe12eSEd Maste 		    ecp->strip == STRIP_UNNEEDED ||
85a85fe12eSEd Maste 		    (ecp->flags & DISCARD_LOCAL))
86a85fe12eSEd Maste 			return (1);
87a85fe12eSEd Maste 		if (ecp->strip == STRIP_NONDEBUG)
88a85fe12eSEd Maste 			return (0);
89a85fe12eSEd Maste 	}
90a85fe12eSEd Maste 
91a85fe12eSEd Maste 	if ((ecp->flags & SEC_REMOVE) || (ecp->flags & SEC_COPY)) {
92a85fe12eSEd Maste 		struct sec_action *sac;
93a85fe12eSEd Maste 
94a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, name, 0);
95a85fe12eSEd Maste 		if ((ecp->flags & SEC_REMOVE) && sac != NULL && sac->remove)
96a85fe12eSEd Maste 			return (1);
97a85fe12eSEd Maste 		if ((ecp->flags & SEC_COPY) && (sac == NULL || !sac->copy))
98a85fe12eSEd Maste 			return (1);
99a85fe12eSEd Maste 	}
100a85fe12eSEd Maste 
101a85fe12eSEd Maste 	return (0);
102a85fe12eSEd Maste }
103a85fe12eSEd Maste 
104a85fe12eSEd Maste /*
105a85fe12eSEd Maste  * Relocation section needs to be removed if the section it applies to
106a85fe12eSEd Maste  * will be removed.
107a85fe12eSEd Maste  */
108a85fe12eSEd Maste int
109a85fe12eSEd Maste is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info)
110a85fe12eSEd Maste {
111a85fe12eSEd Maste 	const char	*name;
112a85fe12eSEd Maste 	GElf_Shdr	 ish;
113a85fe12eSEd Maste 	Elf_Scn		*is;
114a85fe12eSEd Maste 	size_t		 indx;
115a85fe12eSEd Maste 	int		 elferr;
116a85fe12eSEd Maste 
117a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
118a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
119a85fe12eSEd Maste 		    elf_errmsg(-1));
120a85fe12eSEd Maste 
121dc2282fcSMark Johnston 	is = elf_getscn(ecp->ein, sh_info);
122dc2282fcSMark Johnston 	if (is != NULL) {
123a85fe12eSEd Maste 		if (gelf_getshdr(is, &ish) == NULL)
124a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
125a85fe12eSEd Maste 			    elf_errmsg(-1));
126a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) ==
127a85fe12eSEd Maste 		    NULL)
128a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
129a85fe12eSEd Maste 			    elf_errmsg(-1));
130a85fe12eSEd Maste 		if (is_remove_section(ecp, name))
131a85fe12eSEd Maste 			return (1);
132a85fe12eSEd Maste 		else
133a85fe12eSEd Maste 			return (0);
134a85fe12eSEd Maste 	}
135a85fe12eSEd Maste 	elferr = elf_errno();
136a85fe12eSEd Maste 	if (elferr != 0)
137a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
138a85fe12eSEd Maste 		    elf_errmsg(elferr));
139a85fe12eSEd Maste 
140a85fe12eSEd Maste 	/* Remove reloc section if we can't find the target section. */
141a85fe12eSEd Maste 	return (1);
142a85fe12eSEd Maste }
143a85fe12eSEd Maste 
144a85fe12eSEd Maste static int
145a85fe12eSEd Maste is_append_section(struct elfcopy *ecp, const char *name)
146a85fe12eSEd Maste {
147a85fe12eSEd Maste 	struct sec_action *sac;
148a85fe12eSEd Maste 
149a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
150a85fe12eSEd Maste 	if (sac != NULL && sac->append != 0 && sac->string != NULL)
151a85fe12eSEd Maste 		return (1);
152a85fe12eSEd Maste 
153a85fe12eSEd Maste 	return (0);
154a85fe12eSEd Maste }
155a85fe12eSEd Maste 
156a85fe12eSEd Maste static int
157a85fe12eSEd Maste is_compress_section(struct elfcopy *ecp, const char *name)
158a85fe12eSEd Maste {
159a85fe12eSEd Maste 	struct sec_action *sac;
160a85fe12eSEd Maste 
161a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
162a85fe12eSEd Maste 	if (sac != NULL && sac->compress != 0)
163a85fe12eSEd Maste 		return (1);
164a85fe12eSEd Maste 
165a85fe12eSEd Maste 	return (0);
166a85fe12eSEd Maste }
167a85fe12eSEd Maste 
168a85fe12eSEd Maste static void
169a85fe12eSEd Maste check_section_rename(struct elfcopy *ecp, struct section *s)
170a85fe12eSEd Maste {
171a85fe12eSEd Maste 	struct sec_action *sac;
172a85fe12eSEd Maste 	char *prefix;
173a85fe12eSEd Maste 	size_t namelen;
174a85fe12eSEd Maste 
175a85fe12eSEd Maste 	if (s->pseudo)
176a85fe12eSEd Maste 		return;
177a85fe12eSEd Maste 
178a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, s->name, 0);
179a85fe12eSEd Maste 	if (sac != NULL && sac->rename)
180a85fe12eSEd Maste 		s->name = sac->newname;
181a85fe12eSEd Maste 
182a85fe12eSEd Maste 	if (!strcmp(s->name, ".symtab") ||
183a85fe12eSEd Maste 	    !strcmp(s->name, ".strtab") ||
184a85fe12eSEd Maste 	    !strcmp(s->name, ".shstrtab"))
185a85fe12eSEd Maste 		return;
186a85fe12eSEd Maste 
187a85fe12eSEd Maste 	prefix = NULL;
188a85fe12eSEd Maste 	if (s->loadable && ecp->prefix_alloc != NULL)
189a85fe12eSEd Maste 		prefix = ecp->prefix_alloc;
190a85fe12eSEd Maste 	else if (ecp->prefix_sec != NULL)
191a85fe12eSEd Maste 		prefix = ecp->prefix_sec;
192a85fe12eSEd Maste 
193a85fe12eSEd Maste 	if (prefix != NULL) {
194a85fe12eSEd Maste 		namelen = strlen(s->name) + strlen(prefix) + 1;
195a85fe12eSEd Maste 		if ((s->newname = malloc(namelen)) == NULL)
196a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
197a85fe12eSEd Maste 		snprintf(s->newname, namelen, "%s%s", prefix, s->name);
198a85fe12eSEd Maste 		s->name = s->newname;
199a85fe12eSEd Maste 	}
200a85fe12eSEd Maste }
201a85fe12eSEd Maste 
202a85fe12eSEd Maste static int
203a85fe12eSEd Maste get_section_flags(struct elfcopy *ecp, const char *name)
204a85fe12eSEd Maste {
205a85fe12eSEd Maste 	struct sec_action *sac;
206a85fe12eSEd Maste 
207a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
208a85fe12eSEd Maste 	if (sac != NULL && sac->flags)
209a85fe12eSEd Maste 		return sac->flags;
210a85fe12eSEd Maste 
211a85fe12eSEd Maste 	return (0);
212a85fe12eSEd Maste }
213a85fe12eSEd Maste 
214a85fe12eSEd Maste /*
215a85fe12eSEd Maste  * Determine whether the section are debugging section.
216a85fe12eSEd Maste  * According to libbfd, debugging sections are recognized
217a85fe12eSEd Maste  * only by name.
218a85fe12eSEd Maste  */
219a85fe12eSEd Maste static int
220a85fe12eSEd Maste is_debug_section(const char *name)
221a85fe12eSEd Maste {
222a85fe12eSEd Maste 	const char *dbg_sec[] = {
223839529caSEd Maste 		".apple_",
224a85fe12eSEd Maste 		".debug",
225a85fe12eSEd Maste 		".gnu.linkonce.wi.",
226a85fe12eSEd Maste 		".line",
227a85fe12eSEd Maste 		".stab",
228a85fe12eSEd Maste 		NULL
229a85fe12eSEd Maste 	};
230a85fe12eSEd Maste 	const char **p;
231a85fe12eSEd Maste 
232a85fe12eSEd Maste 	for(p = dbg_sec; *p; p++) {
233a85fe12eSEd Maste 		if (strncmp(name, *p, strlen(*p)) == 0)
234a85fe12eSEd Maste 			return (1);
235a85fe12eSEd Maste 	}
236a85fe12eSEd Maste 
237a85fe12eSEd Maste 	return (0);
238a85fe12eSEd Maste }
239a85fe12eSEd Maste 
240a85fe12eSEd Maste static int
24167d97fe7SEd Maste is_dwo_section(const char *name)
24267d97fe7SEd Maste {
24367d97fe7SEd Maste 	size_t len;
24467d97fe7SEd Maste 
24567d97fe7SEd Maste 	if ((len = strlen(name)) > 4 && strcmp(name + len - 4, ".dwo") == 0)
24667d97fe7SEd Maste 		return (1);
24767d97fe7SEd Maste 	return (0);
24867d97fe7SEd Maste }
24967d97fe7SEd Maste 
25067d97fe7SEd Maste static int
251a85fe12eSEd Maste is_print_section(struct elfcopy *ecp, const char *name)
252a85fe12eSEd Maste {
253a85fe12eSEd Maste 	struct sec_action *sac;
254a85fe12eSEd Maste 
255a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
256a85fe12eSEd Maste 	if (sac != NULL && sac->print != 0)
257a85fe12eSEd Maste 		return (1);
258a85fe12eSEd Maste 
259a85fe12eSEd Maste 	return (0);
260a85fe12eSEd Maste }
261a85fe12eSEd Maste 
262a85fe12eSEd Maste static int
263a85fe12eSEd Maste is_modify_section(struct elfcopy *ecp, const char *name)
264a85fe12eSEd Maste {
265a85fe12eSEd Maste 
266a85fe12eSEd Maste 	if (is_append_section(ecp, name) ||
267a85fe12eSEd Maste 	    is_compress_section(ecp, name))
268a85fe12eSEd Maste 		return (1);
269a85fe12eSEd Maste 
270a85fe12eSEd Maste 	return (0);
271a85fe12eSEd Maste }
272a85fe12eSEd Maste 
273a85fe12eSEd Maste struct sec_action*
274a85fe12eSEd Maste lookup_sec_act(struct elfcopy *ecp, const char *name, int add)
275a85fe12eSEd Maste {
276a85fe12eSEd Maste 	struct sec_action *sac;
277a85fe12eSEd Maste 
278a85fe12eSEd Maste 	if (name == NULL)
279a85fe12eSEd Maste 		return NULL;
280a85fe12eSEd Maste 
281a85fe12eSEd Maste 	STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
282a85fe12eSEd Maste 		if (strcmp(name, sac->name) == 0)
283a85fe12eSEd Maste 			return sac;
284a85fe12eSEd Maste 	}
285a85fe12eSEd Maste 
286a85fe12eSEd Maste 	if (add == 0)
287a85fe12eSEd Maste 		return NULL;
288a85fe12eSEd Maste 
289a85fe12eSEd Maste 	if ((sac = malloc(sizeof(*sac))) == NULL)
290a85fe12eSEd Maste 		errx(EXIT_FAILURE, "not enough memory");
291a85fe12eSEd Maste 	memset(sac, 0, sizeof(*sac));
292a85fe12eSEd Maste 	sac->name = name;
293a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list);
294a85fe12eSEd Maste 
295a85fe12eSEd Maste 	return (sac);
296a85fe12eSEd Maste }
297a85fe12eSEd Maste 
298a85fe12eSEd Maste void
299a85fe12eSEd Maste free_sec_act(struct elfcopy *ecp)
300a85fe12eSEd Maste {
301a85fe12eSEd Maste 	struct sec_action *sac, *sac_temp;
302a85fe12eSEd Maste 
303a85fe12eSEd Maste 	STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) {
304a85fe12eSEd Maste 		STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list);
305a85fe12eSEd Maste 		free(sac);
306a85fe12eSEd Maste 	}
307a85fe12eSEd Maste }
308a85fe12eSEd Maste 
309a85fe12eSEd Maste void
310a85fe12eSEd Maste insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail)
311a85fe12eSEd Maste {
312a85fe12eSEd Maste 	struct section *s;
313a85fe12eSEd Maste 
31402816870SMark Johnston 	if (tail || TAILQ_EMPTY(&ecp->v_sec) ||
31502816870SMark Johnston 	    TAILQ_LAST(&ecp->v_sec, sectionlist)->off <= sec->off) {
31602816870SMark Johnston 		TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list);
31702816870SMark Johnston 	} else {
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);
32102816870SMark Johnston 				break;
322a85fe12eSEd Maste 			}
323a85fe12eSEd Maste 		}
324a85fe12eSEd Maste 	}
325a85fe12eSEd Maste 
326a85fe12eSEd Maste 	if (sec->pseudo == 0)
327a85fe12eSEd Maste 		ecp->nos++;
328a85fe12eSEd Maste }
329a85fe12eSEd Maste 
330a85fe12eSEd Maste /*
331a85fe12eSEd Maste  * First step of section creation: create scn and internal section
332a85fe12eSEd Maste  * structure, discard sections to be removed.
333a85fe12eSEd Maste  */
334a85fe12eSEd Maste void
335a85fe12eSEd Maste create_scn(struct elfcopy *ecp)
336a85fe12eSEd Maste {
337a85fe12eSEd Maste 	struct section	*s;
338a85fe12eSEd Maste 	const char	*name;
339a85fe12eSEd Maste 	Elf_Scn		*is;
340a85fe12eSEd Maste 	GElf_Shdr	 ish;
341a85fe12eSEd Maste 	size_t		 indx;
342a85fe12eSEd Maste 	uint64_t	 oldndx, newndx;
343d938d64eSEd Maste 	int		 elferr, sec_flags, reorder;
344a85fe12eSEd Maste 
345a85fe12eSEd Maste 	/*
346a85fe12eSEd Maste 	 * Insert a pseudo section that contains the ELF header
347a85fe12eSEd Maste 	 * and program header. Used as reference for section offset
348a85fe12eSEd Maste 	 * or load address adjustment.
349a85fe12eSEd Maste 	 */
350a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
351a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
352a85fe12eSEd Maste 	s->off = 0;
353a85fe12eSEd Maste 	s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) +
354a85fe12eSEd Maste 	    gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT);
355a85fe12eSEd Maste 	s->align = 1;
356a85fe12eSEd Maste 	s->pseudo = 1;
357a85fe12eSEd Maste 	s->loadable = add_to_inseg_list(ecp, s);
358a85fe12eSEd Maste 	insert_to_sec_list(ecp, s, 0);
359a85fe12eSEd Maste 
360a85fe12eSEd Maste 	/* Create internal .shstrtab section. */
361a85fe12eSEd Maste 	init_shstrtab(ecp);
362a85fe12eSEd Maste 
363a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
364a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
365a85fe12eSEd Maste 		    elf_errmsg(-1));
366a85fe12eSEd Maste 
367d938d64eSEd Maste 	reorder = 0;
368a85fe12eSEd Maste 	is = NULL;
369a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
370a85fe12eSEd Maste 		if (gelf_getshdr(is, &ish) == NULL)
371839529caSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
372a85fe12eSEd Maste 			    elf_errmsg(-1));
373a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL)
374a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
375a85fe12eSEd Maste 			    elf_errmsg(-1));
376a85fe12eSEd Maste 
377a85fe12eSEd Maste 		/* Skip sections to be removed. */
378a85fe12eSEd Maste 		if (is_remove_section(ecp, name))
379a85fe12eSEd Maste 			continue;
380a85fe12eSEd Maste 
381a85fe12eSEd Maste 		/*
382a85fe12eSEd Maste 		 * Relocation section need to be remove if the section
383a85fe12eSEd Maste 		 * it applies will be removed.
384a85fe12eSEd Maste 		 */
385a85fe12eSEd Maste 		if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)
386a85fe12eSEd Maste 			if (ish.sh_info != 0 &&
387a85fe12eSEd Maste 			    is_remove_reloc_sec(ecp, ish.sh_info))
388a85fe12eSEd Maste 				continue;
389a85fe12eSEd Maste 
390cf781b2eSEd Maste 		/*
391cf781b2eSEd Maste 		 * Section groups should be removed if symbol table will
392cf781b2eSEd Maste 		 * be removed. (section group's signature stored in symbol
393cf781b2eSEd Maste 		 * table)
394cf781b2eSEd Maste 		 */
395cf781b2eSEd Maste 		if (ish.sh_type == SHT_GROUP && ecp->strip == STRIP_ALL)
396cf781b2eSEd Maste 			continue;
397cf781b2eSEd Maste 
398a85fe12eSEd Maste 		/* Get section flags set by user. */
399a85fe12eSEd Maste 		sec_flags = get_section_flags(ecp, name);
400a85fe12eSEd Maste 
401a85fe12eSEd Maste 		/* Create internal section object. */
402a85fe12eSEd Maste 		if (strcmp(name, ".shstrtab") != 0) {
403a85fe12eSEd Maste 			if ((s = calloc(1, sizeof(*s))) == NULL)
404a85fe12eSEd Maste 				err(EXIT_FAILURE, "calloc failed");
405a85fe12eSEd Maste 			s->name		= name;
406a85fe12eSEd Maste 			s->is		= is;
407a85fe12eSEd Maste 			s->off		= ish.sh_offset;
408a85fe12eSEd Maste 			s->sz		= ish.sh_size;
409a85fe12eSEd Maste 			s->align	= ish.sh_addralign;
410a85fe12eSEd Maste 			s->type		= ish.sh_type;
41148d41ef0SPhil Shafer 			s->flags	= ish.sh_flags;
412a85fe12eSEd Maste 			s->vma		= ish.sh_addr;
413a85fe12eSEd Maste 
414a85fe12eSEd Maste 			/*
415a85fe12eSEd Maste 			 * Search program headers to determine whether section
416a85fe12eSEd Maste 			 * is loadable, but if user explicitly set section flags
417a85fe12eSEd Maste 			 * while neither "load" nor "alloc" is set, we make the
418a85fe12eSEd Maste 			 * section unloadable.
419839529caSEd Maste 			 *
420839529caSEd Maste 			 * Sections in relocatable object is loadable if
421839529caSEd Maste 			 * section flag SHF_ALLOC is set.
422a85fe12eSEd Maste 			 */
423a85fe12eSEd Maste 			if (sec_flags &&
424a85fe12eSEd Maste 			    (sec_flags & (SF_LOAD | SF_ALLOC)) == 0)
425a85fe12eSEd Maste 				s->loadable = 0;
426839529caSEd Maste 			else {
427a85fe12eSEd Maste 				s->loadable = add_to_inseg_list(ecp, s);
428839529caSEd Maste 				if ((ecp->flags & RELOCATABLE) &&
429839529caSEd Maste 				    (ish.sh_flags & SHF_ALLOC))
430839529caSEd Maste 					s->loadable = 1;
431839529caSEd Maste 			}
432a85fe12eSEd Maste 		} else {
433a85fe12eSEd Maste 			/* Assuming .shstrtab is "unloadable". */
434a85fe12eSEd Maste 			s		= ecp->shstrtab;
435a85fe12eSEd Maste 			s->off		= ish.sh_offset;
436a85fe12eSEd Maste 		}
437a85fe12eSEd Maste 
438a85fe12eSEd Maste 		oldndx = newndx = SHN_UNDEF;
439a85fe12eSEd Maste 		if (strcmp(name, ".symtab") != 0 &&
440a85fe12eSEd Maste 		    strcmp(name, ".strtab") != 0) {
441a85fe12eSEd Maste 			if (!strcmp(name, ".shstrtab")) {
442a85fe12eSEd Maste 				/*
443a85fe12eSEd Maste 				 * Add sections specified by --add-section and
444a85fe12eSEd Maste 				 * gnu debuglink. we want these sections have
445a85fe12eSEd Maste 				 * smaller index than .shstrtab section.
446a85fe12eSEd Maste 				 */
447a85fe12eSEd Maste 				if (ecp->debuglink != NULL)
448a85fe12eSEd Maste 					add_gnu_debuglink(ecp);
449a85fe12eSEd Maste 				if (ecp->flags & SEC_ADD)
450a85fe12eSEd Maste 					insert_sections(ecp);
451a85fe12eSEd Maste 			}
452a85fe12eSEd Maste  			if ((s->os = elf_newscn(ecp->eout)) == NULL)
453a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_newscn failed: %s",
454a85fe12eSEd Maste 				    elf_errmsg(-1));
455a85fe12eSEd Maste 			if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF)
456a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
457a85fe12eSEd Maste 				    elf_errmsg(-1));
458a85fe12eSEd Maste 		}
459a85fe12eSEd Maste 		if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF)
460a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
461a85fe12eSEd Maste 			    elf_errmsg(-1));
462a85fe12eSEd Maste 		if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF)
463a85fe12eSEd Maste 			ecp->secndx[oldndx] = newndx;
464a85fe12eSEd Maste 
465a85fe12eSEd Maste 		/*
466a85fe12eSEd Maste 		 * If strip action is STRIP_NONDEBUG(only keep debug),
46795fd7f26SEd Maste 		 * change sections type of loadable sections and section
46895fd7f26SEd Maste 		 * groups to SHT_NOBITS, and the content of those sections
46995fd7f26SEd Maste 		 * will be discarded. However, SHT_NOTE sections should
47095fd7f26SEd Maste 		 * be kept.
471a85fe12eSEd Maste 		 */
47295fd7f26SEd Maste 		if (ecp->strip == STRIP_NONDEBUG) {
47395fd7f26SEd Maste 			if (((ish.sh_flags & SHF_ALLOC) ||
47495fd7f26SEd Maste 			    (ish.sh_flags & SHF_GROUP)) &&
47595fd7f26SEd Maste 			    ish.sh_type != SHT_NOTE)
476a85fe12eSEd Maste 				s->type = SHT_NOBITS;
47795fd7f26SEd Maste 		}
478a85fe12eSEd Maste 
479a85fe12eSEd Maste 		check_section_rename(ecp, s);
480a85fe12eSEd Maste 
481a85fe12eSEd Maste 		/* create section header based on input object. */
482a85fe12eSEd Maste 		if (strcmp(name, ".symtab") != 0 &&
483a85fe12eSEd Maste 		    strcmp(name, ".strtab") != 0 &&
484d938d64eSEd Maste 		    strcmp(name, ".shstrtab") != 0) {
485a85fe12eSEd Maste 			copy_shdr(ecp, s, NULL, 0, sec_flags);
486d938d64eSEd Maste 			/*
487d938d64eSEd Maste 			 * elfcopy puts .symtab, .strtab and .shstrtab
488d938d64eSEd Maste 			 * sections in the end of the output object.
489d938d64eSEd Maste 			 * If the input objects have more sections
490d938d64eSEd Maste 			 * after any of these 3 sections, the section
491d938d64eSEd Maste 			 * table will be reordered. section symbols
492d938d64eSEd Maste 			 * should be regenerated for relocations.
493d938d64eSEd Maste 			 */
494d938d64eSEd Maste 			if (reorder)
495d938d64eSEd Maste 				ecp->flags &= ~SYMTAB_INTACT;
496d938d64eSEd Maste 		} else
497d938d64eSEd Maste 			reorder = 1;
498a85fe12eSEd Maste 
499a85fe12eSEd Maste 		if (strcmp(name, ".symtab") == 0) {
500a85fe12eSEd Maste 			ecp->flags |= SYMTAB_EXIST;
501a85fe12eSEd Maste 			ecp->symtab = s;
502a85fe12eSEd Maste 		}
503a85fe12eSEd Maste 		if (strcmp(name, ".strtab") == 0)
504a85fe12eSEd Maste 			ecp->strtab = s;
505a85fe12eSEd Maste 
506a85fe12eSEd Maste 		insert_to_sec_list(ecp, s, 0);
507a85fe12eSEd Maste 	}
508a85fe12eSEd Maste 	elferr = elf_errno();
509a85fe12eSEd Maste 	if (elferr != 0)
510a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
511a85fe12eSEd Maste 		    elf_errmsg(elferr));
512a85fe12eSEd Maste }
513a85fe12eSEd Maste 
514a85fe12eSEd Maste struct section *
515a85fe12eSEd Maste insert_shtab(struct elfcopy *ecp, int tail)
516a85fe12eSEd Maste {
517a85fe12eSEd Maste 	struct section	*s, *shtab;
518a85fe12eSEd Maste 	GElf_Ehdr	 ieh;
519a85fe12eSEd Maste 	int		 nsecs;
520a85fe12eSEd Maste 
521a85fe12eSEd Maste 	/*
522a85fe12eSEd Maste 	 * Treat section header table as a "pseudo" section, insert it
523a85fe12eSEd Maste 	 * into section list, so later it will get sorted and resynced
524a85fe12eSEd Maste 	 * just as normal sections.
525a85fe12eSEd Maste 	 */
526a85fe12eSEd Maste 	if ((shtab = calloc(1, sizeof(*shtab))) == NULL)
527a85fe12eSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
528a85fe12eSEd Maste 	if (!tail) {
5294a85c691SEd Maste 		/*
5304a85c691SEd Maste 		 * "shoff" of input object is used as a hint for section
5314a85c691SEd Maste 		 * resync later.
5324a85c691SEd Maste 		 */
533a85fe12eSEd Maste 		if (gelf_getehdr(ecp->ein, &ieh) == NULL)
534a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
535a85fe12eSEd Maste 			    elf_errmsg(-1));
536a85fe12eSEd Maste 		shtab->off = ieh.e_shoff;
537a85fe12eSEd Maste 	} else
538a85fe12eSEd Maste 		shtab->off = 0;
539a85fe12eSEd Maste 	/* Calculate number of sections in the output object. */
540a85fe12eSEd Maste 	nsecs = 0;
541a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
542a85fe12eSEd Maste 		if (!s->pseudo)
543a85fe12eSEd Maste 			nsecs++;
544a85fe12eSEd Maste 	}
545a85fe12eSEd Maste 	/* Remember there is always a null section, so we +1 here. */
546a85fe12eSEd Maste 	shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT);
547a85fe12eSEd Maste 	if (shtab->sz == 0)
548a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
549a85fe12eSEd Maste 	shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8);
550a85fe12eSEd Maste 	shtab->loadable = 0;
551a85fe12eSEd Maste 	shtab->pseudo = 1;
552a85fe12eSEd Maste 	insert_to_sec_list(ecp, shtab, tail);
553a85fe12eSEd Maste 
554a85fe12eSEd Maste 	return (shtab);
555a85fe12eSEd Maste }
556a85fe12eSEd Maste 
557a85fe12eSEd Maste void
558a85fe12eSEd Maste copy_content(struct elfcopy *ecp)
559a85fe12eSEd Maste {
560a85fe12eSEd Maste 	struct section *s;
561a85fe12eSEd Maste 
562a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
563a85fe12eSEd Maste 		/* Skip pseudo section. */
564a85fe12eSEd Maste 		if (s->pseudo)
565a85fe12eSEd Maste 			continue;
566a85fe12eSEd Maste 
567a85fe12eSEd Maste 		/* Skip special sections. */
568a85fe12eSEd Maste 		if (strcmp(s->name, ".symtab") == 0 ||
569a85fe12eSEd Maste 		    strcmp(s->name, ".strtab") == 0 ||
570a85fe12eSEd Maste 		    strcmp(s->name, ".shstrtab") == 0)
571a85fe12eSEd Maste 			continue;
572a85fe12eSEd Maste 
573a85fe12eSEd Maste 		/*
574aee4c74cSEd Maste 		 * If strip action is STRIP_ALL, relocation info need
575aee4c74cSEd Maste 		 * to be stripped. Skip filtering otherwisw.
576aee4c74cSEd Maste 		 */
577aee4c74cSEd Maste 		if (ecp->strip == STRIP_ALL &&
578aee4c74cSEd Maste 		    (s->type == SHT_REL || s->type == SHT_RELA))
579aee4c74cSEd Maste 			filter_reloc(ecp, s);
580aee4c74cSEd Maste 
581aee4c74cSEd Maste 		/*
5823ef90571SEd Maste 		 * The section indices in the SHT_GROUP section needs
5833ef90571SEd Maste 		 * to be updated since we might have stripped some
5843ef90571SEd Maste 		 * sections and changed section numbering.
5853ef90571SEd Maste 		 */
5863ef90571SEd Maste 		if (s->type == SHT_GROUP)
5873ef90571SEd Maste 			update_section_group(ecp, s);
5883ef90571SEd Maste 
589a85fe12eSEd Maste 		if (is_modify_section(ecp, s->name))
590a85fe12eSEd Maste 			modify_section(ecp, s);
591a85fe12eSEd Maste 
592a85fe12eSEd Maste 		copy_data(s);
593a85fe12eSEd Maste 
594a85fe12eSEd Maste 		/*
595a85fe12eSEd Maste 		 * If symbol table is modified, relocation info might
596a85fe12eSEd Maste 		 * need update, as symbol index may have changed.
597a85fe12eSEd Maste 		 */
598a85fe12eSEd Maste 		if ((ecp->flags & SYMTAB_INTACT) == 0 &&
599a85fe12eSEd Maste 		    (ecp->flags & SYMTAB_EXIST) &&
600a85fe12eSEd Maste 		    (s->type == SHT_REL || s->type == SHT_RELA))
601a85fe12eSEd Maste 			update_reloc(ecp, s);
602a85fe12eSEd Maste 
603a85fe12eSEd Maste 		if (is_print_section(ecp, s->name))
604a85fe12eSEd Maste 			print_section(s);
605a85fe12eSEd Maste 	}
606a85fe12eSEd Maste }
607a85fe12eSEd Maste 
6083ef90571SEd Maste 
6093ef90571SEd Maste /*
6103ef90571SEd Maste  * Update section group section. The section indices in the SHT_GROUP
6113ef90571SEd Maste  * section need update after section numbering changed.
6123ef90571SEd Maste  */
6133ef90571SEd Maste static void
6143ef90571SEd Maste update_section_group(struct elfcopy *ecp, struct section *s)
6153ef90571SEd Maste {
6163ef90571SEd Maste 	GElf_Shdr	 ish;
6173ef90571SEd Maste 	Elf_Data	*id;
6183ef90571SEd Maste 	uint32_t	*ws, *wd;
6193ef90571SEd Maste 	uint64_t	 n;
6203ef90571SEd Maste 	size_t		 ishnum;
6213ef90571SEd Maste 	int		 i, j;
6223ef90571SEd Maste 
6233ef90571SEd Maste 	if (!elf_getshnum(ecp->ein, &ishnum))
6243ef90571SEd Maste 		errx(EXIT_FAILURE, "elf_getshnum failed: %s",
6253ef90571SEd Maste 		    elf_errmsg(-1));
6263ef90571SEd Maste 
6273ef90571SEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
6283ef90571SEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
6293ef90571SEd Maste 		    elf_errmsg(-1));
6303ef90571SEd Maste 
6313ef90571SEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL)
6323ef90571SEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
6333ef90571SEd Maste 		    elf_errmsg(-1));
6343ef90571SEd Maste 
6353ef90571SEd Maste 	if (ish.sh_size == 0)
6363ef90571SEd Maste 		return;
6373ef90571SEd Maste 
6383ef90571SEd Maste 	if (ish.sh_entsize == 0)
6393ef90571SEd Maste 		ish.sh_entsize = 4;
6403ef90571SEd Maste 
6413ef90571SEd Maste 	ws = id->d_buf;
6423ef90571SEd Maste 
6433ef90571SEd Maste 	/* We only support COMDAT section. */
6443ef90571SEd Maste #ifndef GRP_COMDAT
6453ef90571SEd Maste #define	GRP_COMDAT 0x1
6463ef90571SEd Maste #endif
6473ef90571SEd Maste 	if ((*ws & GRP_COMDAT) == 0)
6483ef90571SEd Maste 		return;
6493ef90571SEd Maste 
6503ef90571SEd Maste 	if ((s->buf = malloc(ish.sh_size)) == NULL)
6513ef90571SEd Maste 		err(EXIT_FAILURE, "malloc failed");
6523ef90571SEd Maste 
6533ef90571SEd Maste 	s->sz = ish.sh_size;
6543ef90571SEd Maste 
6553ef90571SEd Maste 	wd = s->buf;
6563ef90571SEd Maste 
6573ef90571SEd Maste 	/* Copy the flag word as-is. */
6583ef90571SEd Maste 	*wd = *ws;
6593ef90571SEd Maste 
6603ef90571SEd Maste 	/* Update the section indices. */
6613ef90571SEd Maste 	n = ish.sh_size / ish.sh_entsize;
6623ef90571SEd Maste 	for(i = 1, j = 1; (uint64_t)i < n; i++) {
6633ef90571SEd Maste 		if (ws[i] != SHN_UNDEF && ws[i] < ishnum &&
6643ef90571SEd Maste 		    ecp->secndx[ws[i]] != 0)
6653ef90571SEd Maste 			wd[j++] = ecp->secndx[ws[i]];
6663ef90571SEd Maste 		else
6673ef90571SEd Maste 			s->sz -= 4;
6683ef90571SEd Maste 	}
6693ef90571SEd Maste 
6703ef90571SEd Maste 	s->nocopy = 1;
6713ef90571SEd Maste }
6723ef90571SEd Maste 
673aee4c74cSEd Maste /*
674aee4c74cSEd Maste  * Filter relocation entries, only keep those entries whose
675aee4c74cSEd Maste  * symbol is in the keep list.
676aee4c74cSEd Maste  */
677aee4c74cSEd Maste static void
678aee4c74cSEd Maste filter_reloc(struct elfcopy *ecp, struct section *s)
679aee4c74cSEd Maste {
680aee4c74cSEd Maste 	const char	*name;
681aee4c74cSEd Maste 	GElf_Shdr	 ish;
682aee4c74cSEd Maste 	GElf_Rel	 rel;
683aee4c74cSEd Maste 	GElf_Rela	 rela;
684aee4c74cSEd Maste 	Elf32_Rel	*rel32;
685aee4c74cSEd Maste 	Elf64_Rel	*rel64;
686aee4c74cSEd Maste 	Elf32_Rela	*rela32;
687aee4c74cSEd Maste 	Elf64_Rela	*rela64;
688aee4c74cSEd Maste 	Elf_Data	*id;
689aee4c74cSEd Maste 	uint64_t	 cap, n, nrels, sym;
690aee4c74cSEd Maste 	int		 elferr, i;
691aee4c74cSEd Maste 
692aee4c74cSEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
693aee4c74cSEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
694aee4c74cSEd Maste 		    elf_errmsg(-1));
695aee4c74cSEd Maste 
696aee4c74cSEd Maste 	/* We don't want to touch relocation info for dynamic symbols. */
697aee4c74cSEd Maste 	if ((ecp->flags & SYMTAB_EXIST) == 0) {
698aee4c74cSEd Maste 		/*
699aee4c74cSEd Maste 		 * No symbol table in output.  If sh_link points to a section
700aee4c74cSEd Maste 		 * that exists in the output object, this relocation section
701aee4c74cSEd Maste 		 * is for dynamic symbols.  Don't touch it.
702aee4c74cSEd Maste 		 */
703aee4c74cSEd Maste 		if (ish.sh_link != 0 && ecp->secndx[ish.sh_link] != 0)
704aee4c74cSEd Maste 			return;
705aee4c74cSEd Maste 	} else {
706aee4c74cSEd Maste 		/* Symbol table exist, check if index equals. */
707aee4c74cSEd Maste 		if (ish.sh_link != elf_ndxscn(ecp->symtab->is))
708aee4c74cSEd Maste 			return;
709aee4c74cSEd Maste 	}
710aee4c74cSEd Maste 
711aee4c74cSEd Maste #define	COPYREL(REL, SZ) do {					\
712aee4c74cSEd Maste 	if (nrels == 0) {					\
713aee4c74cSEd Maste 		if ((REL##SZ = malloc(cap *			\
714aee4c74cSEd Maste 		    sizeof(*REL##SZ))) == NULL)			\
715aee4c74cSEd Maste 			err(EXIT_FAILURE, "malloc failed");	\
716aee4c74cSEd Maste 	}							\
717aee4c74cSEd Maste 	if (nrels >= cap) {					\
718aee4c74cSEd Maste 		cap *= 2;					\
719aee4c74cSEd Maste 		if ((REL##SZ = realloc(REL##SZ, cap *		\
720aee4c74cSEd Maste 		    sizeof(*REL##SZ))) == NULL)			\
721aee4c74cSEd Maste 			err(EXIT_FAILURE, "realloc failed");	\
722aee4c74cSEd Maste 	}							\
723aee4c74cSEd Maste 	REL##SZ[nrels].r_offset = REL.r_offset;			\
724aee4c74cSEd Maste 	REL##SZ[nrels].r_info	= REL.r_info;			\
725aee4c74cSEd Maste 	if (s->type == SHT_RELA)				\
726aee4c74cSEd Maste 		rela##SZ[nrels].r_addend = rela.r_addend;	\
727aee4c74cSEd Maste 	nrels++;						\
728aee4c74cSEd Maste } while (0)
729aee4c74cSEd Maste 
730aee4c74cSEd Maste 	nrels = 0;
731aee4c74cSEd Maste 	cap = 4;		/* keep list is usually small. */
732aee4c74cSEd Maste 	rel32 = NULL;
733aee4c74cSEd Maste 	rel64 = NULL;
734aee4c74cSEd Maste 	rela32 = NULL;
735aee4c74cSEd Maste 	rela64 = NULL;
736aee4c74cSEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL)
737aee4c74cSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
738aee4c74cSEd Maste 		    elf_errmsg(-1));
739aee4c74cSEd Maste 	n = ish.sh_size / ish.sh_entsize;
740aee4c74cSEd Maste 	for(i = 0; (uint64_t)i < n; i++) {
741aee4c74cSEd Maste 		if (s->type == SHT_REL) {
742aee4c74cSEd Maste 			if (gelf_getrel(id, i, &rel) != &rel)
743aee4c74cSEd Maste 				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
744aee4c74cSEd Maste 				    elf_errmsg(-1));
745aee4c74cSEd Maste 			sym = GELF_R_SYM(rel.r_info);
746aee4c74cSEd Maste 		} else {
747aee4c74cSEd Maste 			if (gelf_getrela(id, i, &rela) != &rela)
748aee4c74cSEd Maste 				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
749aee4c74cSEd Maste 				    elf_errmsg(-1));
750aee4c74cSEd Maste 			sym = GELF_R_SYM(rela.r_info);
751aee4c74cSEd Maste 		}
752aee4c74cSEd Maste 		/*
753aee4c74cSEd Maste 		 * If a relocation references a symbol and we are omitting
754aee4c74cSEd Maste 		 * either that symbol or the entire symbol table we cannot
755aee4c74cSEd Maste 		 * produce valid output, and so just omit the relocation.
756aee4c74cSEd Maste 		 * Broken output like this is generally not useful, but some
757aee4c74cSEd Maste 		 * uses of elfcopy/strip rely on it - for example, GCC's build
758aee4c74cSEd Maste 		 * process uses it to check for build reproducibility by
759aee4c74cSEd Maste 		 * stripping objects and comparing them.
760aee4c74cSEd Maste 		 *
761aee4c74cSEd Maste 		 * Relocations that do not reference a symbol are retained.
762aee4c74cSEd Maste 		 */
763aee4c74cSEd Maste 		if (sym != 0) {
764aee4c74cSEd Maste 			if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0)
765aee4c74cSEd Maste 				continue;
766aee4c74cSEd Maste 			name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is),
767aee4c74cSEd Maste 			    sym);
768aee4c74cSEd Maste 			if (name == NULL)
769aee4c74cSEd Maste 				errx(EXIT_FAILURE, "elf_strptr failed: %s",
770aee4c74cSEd Maste 				    elf_errmsg(-1));
771aee4c74cSEd Maste 			if (lookup_symop_list(ecp, name, SYMOP_KEEP) == NULL)
772aee4c74cSEd Maste 				continue;
773aee4c74cSEd Maste 		}
774aee4c74cSEd Maste 		if (ecp->oec == ELFCLASS32) {
775aee4c74cSEd Maste 			if (s->type == SHT_REL)
776aee4c74cSEd Maste 				COPYREL(rel, 32);
777aee4c74cSEd Maste 			else
778aee4c74cSEd Maste 				COPYREL(rela, 32);
779aee4c74cSEd Maste 		} else {
780aee4c74cSEd Maste 			if (s->type == SHT_REL)
781aee4c74cSEd Maste 				COPYREL(rel, 64);
782aee4c74cSEd Maste 			else
783aee4c74cSEd Maste 				COPYREL(rela, 64);
784aee4c74cSEd Maste 		}
785aee4c74cSEd Maste 	}
786aee4c74cSEd Maste 	elferr = elf_errno();
787aee4c74cSEd Maste 	if (elferr != 0)
788aee4c74cSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
789aee4c74cSEd Maste 		    elf_errmsg(elferr));
790aee4c74cSEd Maste 
791aee4c74cSEd Maste 	if (ecp->oec == ELFCLASS32) {
792aee4c74cSEd Maste 		if (s->type == SHT_REL)
793aee4c74cSEd Maste 			s->buf = rel32;
794aee4c74cSEd Maste 		else
795aee4c74cSEd Maste 			s->buf = rela32;
796aee4c74cSEd Maste 	} else {
797aee4c74cSEd Maste 		if (s->type == SHT_REL)
798aee4c74cSEd Maste 			s->buf = rel64;
799aee4c74cSEd Maste 		else
800aee4c74cSEd Maste 			s->buf = rela64;
801aee4c74cSEd Maste 	}
802aee4c74cSEd Maste 	s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL :
803aee4c74cSEd Maste 	    ELF_T_RELA), nrels, EV_CURRENT);
804aee4c74cSEd Maste 	s->nocopy = 1;
805aee4c74cSEd Maste }
806aee4c74cSEd Maste 
807a85fe12eSEd Maste static void
808a85fe12eSEd Maste update_reloc(struct elfcopy *ecp, struct section *s)
809a85fe12eSEd Maste {
810a85fe12eSEd Maste 	GElf_Shdr	 osh;
811a85fe12eSEd Maste 	GElf_Rel	 rel;
812a85fe12eSEd Maste 	GElf_Rela	 rela;
813a85fe12eSEd Maste 	Elf_Data	*od;
814a85fe12eSEd Maste 	uint64_t	 n;
815a85fe12eSEd Maste 	int		 i;
816a85fe12eSEd Maste 
817a85fe12eSEd Maste #define UPDATEREL(REL) do {						\
818a85fe12eSEd Maste 	if (gelf_get##REL(od, i, &REL) != &REL)				\
819a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_get##REL failed: %s",		\
820a85fe12eSEd Maste 		    elf_errmsg(-1));					\
821a85fe12eSEd Maste 	REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)],	\
822a85fe12eSEd Maste 	    GELF_R_TYPE(REL.r_info));					\
823a85fe12eSEd Maste 	if (!gelf_update_##REL(od, i, &REL))				\
824a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_##REL failed: %s",	\
825a85fe12eSEd Maste 		    elf_errmsg(-1));					\
826a85fe12eSEd Maste } while(0)
827a85fe12eSEd Maste 
828a85fe12eSEd Maste 	if (s->sz == 0)
829a85fe12eSEd Maste 		return;
830a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
831a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
832a85fe12eSEd Maste 		    elf_errmsg(-1));
833a85fe12eSEd Maste 	/* Only process .symtab reloc info. */
834a85fe12eSEd Maste 	if (osh.sh_link != elf_ndxscn(ecp->symtab->is))
835a85fe12eSEd Maste 		return;
836a85fe12eSEd Maste 	if ((od = elf_getdata(s->os, NULL)) == NULL)
837a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
838a85fe12eSEd Maste 		    elf_errmsg(-1));
839a85fe12eSEd Maste 	n = osh.sh_size / osh.sh_entsize;
840a85fe12eSEd Maste 	for(i = 0; (uint64_t)i < n; i++) {
841a85fe12eSEd Maste 		if (s->type == SHT_REL)
842a85fe12eSEd Maste 			UPDATEREL(rel);
843a85fe12eSEd Maste 		else
844a85fe12eSEd Maste 			UPDATEREL(rela);
845a85fe12eSEd Maste 	}
846a85fe12eSEd Maste }
847a85fe12eSEd Maste 
848a85fe12eSEd Maste static void
849a85fe12eSEd Maste pad_section(struct elfcopy *ecp, struct section *s)
850a85fe12eSEd Maste {
851a85fe12eSEd Maste 	GElf_Shdr	 osh;
852a85fe12eSEd Maste 	Elf_Data	*od;
853a85fe12eSEd Maste 
854a85fe12eSEd Maste 	if (s == NULL || s->pad_sz == 0)
855a85fe12eSEd Maste 		return;
856a85fe12eSEd Maste 
857a85fe12eSEd Maste 	if ((s->pad = malloc(s->pad_sz)) == NULL)
858a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
859a85fe12eSEd Maste 	memset(s->pad, ecp->fill, s->pad_sz);
860a85fe12eSEd Maste 
861a85fe12eSEd Maste 	/* Create a new Elf_Data to contain the padding bytes. */
862a85fe12eSEd Maste 	if ((od = elf_newdata(s->os)) == NULL)
863a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
864a85fe12eSEd Maste 		    elf_errmsg(-1));
865a85fe12eSEd Maste 	od->d_align = 1;
866a85fe12eSEd Maste 	od->d_off = s->sz;
867a85fe12eSEd Maste 	od->d_buf = s->pad;
868a85fe12eSEd Maste 	od->d_type = ELF_T_BYTE;
869a85fe12eSEd Maste 	od->d_size = s->pad_sz;
870a85fe12eSEd Maste 	od->d_version = EV_CURRENT;
871a85fe12eSEd Maste 
872a85fe12eSEd Maste 	/* Update section header. */
873a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
874a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
875a85fe12eSEd Maste 		    elf_errmsg(-1));
876a85fe12eSEd Maste 	osh.sh_size = s->sz + s->pad_sz;
877a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &osh))
878a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
879a85fe12eSEd Maste 		    elf_errmsg(-1));
880a85fe12eSEd Maste }
881a85fe12eSEd Maste 
8824133f236SEd Maste static int
8834133f236SEd Maste section_type_alignment(int sht, int class)
8844133f236SEd Maste {
8854133f236SEd Maste 	switch (sht)
8864133f236SEd Maste 	{
8874133f236SEd Maste 	case SHT_DYNAMIC:
8884133f236SEd Maste 	case SHT_DYNSYM:
8894133f236SEd Maste 	case SHT_FINI_ARRAY:
8904133f236SEd Maste 	case SHT_GNU_HASH:
8914133f236SEd Maste 	case SHT_INIT_ARRAY:
8924133f236SEd Maste 	case SHT_PREINIT_ARRAY:
8934133f236SEd Maste 	case SHT_REL:
8944133f236SEd Maste 	case SHT_RELA:
8954133f236SEd Maste 	case SHT_SYMTAB:
8964133f236SEd Maste 		return (class == ELFCLASS64 ? 8 : 4);
8974133f236SEd Maste 	case SHT_SUNW_move:
8984133f236SEd Maste 		return (8);
8994133f236SEd Maste 	case SHT_GNU_LIBLIST:
9004133f236SEd Maste 	case SHT_GROUP:
9014133f236SEd Maste 	case SHT_HASH:
9024133f236SEd Maste 	case SHT_NOTE:
9034133f236SEd Maste 	case SHT_SUNW_verdef:	/* == SHT_GNU_verdef */
9044133f236SEd Maste 	case SHT_SUNW_verneed:	/* == SHT_GNU_verneed */
9054133f236SEd Maste 	case SHT_SYMTAB_SHNDX:
9064133f236SEd Maste 		return (4);
9074133f236SEd Maste 	case SHT_SUNW_syminfo:
9084133f236SEd Maste 	case SHT_SUNW_versym:	/* == SHT_GNU_versym */
9094133f236SEd Maste 		return (2);
9104133f236SEd Maste 	case SHT_NOBITS:
9114133f236SEd Maste 	case SHT_PROGBITS:
9124133f236SEd Maste 	case SHT_STRTAB:
9134133f236SEd Maste 	case SHT_SUNW_dof:
9144133f236SEd Maste 		return (1);
9154133f236SEd Maste 	}
9164133f236SEd Maste 	return (1);
9174133f236SEd Maste }
9184133f236SEd Maste 
919a85fe12eSEd Maste void
920a85fe12eSEd Maste resync_sections(struct elfcopy *ecp)
921a85fe12eSEd Maste {
922a85fe12eSEd Maste 	struct section	*s, *ps;
923a85fe12eSEd Maste 	GElf_Shdr	 osh;
924a85fe12eSEd Maste 	uint64_t	 off;
925a85fe12eSEd Maste 	int		 first;
9264133f236SEd Maste 	int		 min_alignment;
927a85fe12eSEd Maste 
928a85fe12eSEd Maste 	ps = NULL;
929a85fe12eSEd Maste 	first = 1;
930a85fe12eSEd Maste 	off = 0;
931a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
932a85fe12eSEd Maste 		if (first) {
933a85fe12eSEd Maste 			off = s->off;
934a85fe12eSEd Maste 			first = 0;
935a85fe12eSEd Maste 		}
936a85fe12eSEd Maste 
9374a85c691SEd Maste 		/*
9384a85c691SEd Maste 		 * Ignore TLS sections with load address 0 and without
9394a85c691SEd Maste 		 * content. We don't need to adjust their file offset or
9404a85c691SEd Maste 		 * VMA, only the size matters.
9414a85c691SEd Maste 		 */
9424a85c691SEd Maste 		if (s->seg_tls != NULL && s->type == SHT_NOBITS &&
9434a85c691SEd Maste 		    s->off == 0)
9444a85c691SEd Maste 			continue;
9454a85c691SEd Maste 
946a85fe12eSEd Maste 		/* Align section offset. */
9472b39d4f6SEd Maste 		if (s->align == 0)
9482b39d4f6SEd Maste 			s->align = 1;
9494133f236SEd Maste 		min_alignment = section_type_alignment(s->type, ecp->oec);
9504133f236SEd Maste 		if (s->align < INT_MAX && (int)s->align < min_alignment) {
9514133f236SEd Maste 			warnx("section %s alignment %d increased to %d",
9524133f236SEd Maste 			    s->name, (int)s->align, min_alignment);
9534133f236SEd Maste 			s->align = min_alignment;
9544133f236SEd Maste 		}
955a85fe12eSEd Maste 		if (off <= s->off) {
956839529caSEd Maste 			if (!s->loadable || (ecp->flags & RELOCATABLE))
957a85fe12eSEd Maste 				s->off = roundup(off, s->align);
958a85fe12eSEd Maste 		} else {
959839529caSEd Maste 			if (s->loadable && (ecp->flags & RELOCATABLE) == 0)
96017eee522SEd Maste 				warnx("moving loadable section %s, "
96117eee522SEd Maste 				    "is this intentional?", s->name);
962a85fe12eSEd Maste 			s->off = roundup(off, s->align);
963a85fe12eSEd Maste 		}
964a85fe12eSEd Maste 
965a85fe12eSEd Maste 		/* Calculate next section offset. */
966a85fe12eSEd Maste 		off = s->off;
967a85fe12eSEd Maste 		if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL))
968a85fe12eSEd Maste 			off += s->sz;
969a85fe12eSEd Maste 
970a85fe12eSEd Maste 		if (s->pseudo) {
971a85fe12eSEd Maste 			ps = NULL;
972a85fe12eSEd Maste 			continue;
973a85fe12eSEd Maste 		}
974a85fe12eSEd Maste 
975a85fe12eSEd Maste 		/* Count padding bytes added through --pad-to. */
976a85fe12eSEd Maste 		if (s->pad_sz > 0)
977a85fe12eSEd Maste 			off += s->pad_sz;
978a85fe12eSEd Maste 
979a85fe12eSEd Maste 		/* Update section header accordingly. */
980a85fe12eSEd Maste 		if (gelf_getshdr(s->os, &osh) == NULL)
981a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
982a85fe12eSEd Maste 			    elf_errmsg(-1));
983a85fe12eSEd Maste 		osh.sh_addr = s->vma;
9844133f236SEd Maste 		osh.sh_addralign = s->align;
985a85fe12eSEd Maste 		osh.sh_offset = s->off;
986a85fe12eSEd Maste 		osh.sh_size = s->sz;
987a85fe12eSEd Maste 		if (!gelf_update_shdr(s->os, &osh))
988a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
989a85fe12eSEd Maste 			    elf_errmsg(-1));
990a85fe12eSEd Maste 
991a85fe12eSEd Maste 		/* Add padding for previous section, if need. */
992a85fe12eSEd Maste 		if (ps != NULL) {
993a85fe12eSEd Maste 			if (ps->pad_sz > 0) {
994a85fe12eSEd Maste 				/* Apply padding added by --pad-to. */
995a85fe12eSEd Maste 				pad_section(ecp, ps);
996a85fe12eSEd Maste 			} else if ((ecp->flags & GAP_FILL) &&
997a85fe12eSEd Maste 			    (ps->off + ps->sz < s->off)) {
998a85fe12eSEd Maste 				/*
999a85fe12eSEd Maste 				 * Fill the gap between sections by padding
1000a85fe12eSEd Maste 				 * the section with lower address.
1001a85fe12eSEd Maste 				 */
1002a85fe12eSEd Maste 				ps->pad_sz = s->off - (ps->off + ps->sz);
1003a85fe12eSEd Maste 				pad_section(ecp, ps);
1004a85fe12eSEd Maste 			}
1005a85fe12eSEd Maste 		}
1006a85fe12eSEd Maste 
1007a85fe12eSEd Maste 		ps = s;
1008a85fe12eSEd Maste 	}
1009a85fe12eSEd Maste 
1010a85fe12eSEd Maste 	/* Pad the last section, if need. */
1011a85fe12eSEd Maste 	if (ps != NULL && ps->pad_sz > 0)
1012a85fe12eSEd Maste 		pad_section(ecp, ps);
1013a85fe12eSEd Maste }
1014a85fe12eSEd Maste 
1015a85fe12eSEd Maste static void
1016a85fe12eSEd Maste modify_section(struct elfcopy *ecp, struct section *s)
1017a85fe12eSEd Maste {
1018a85fe12eSEd Maste 	struct sec_action	*sac;
1019a85fe12eSEd Maste 	size_t			 srcsz, dstsz, p, len;
1020a85fe12eSEd Maste 	char			*b, *c, *d, *src, *end;
1021a85fe12eSEd Maste 	int			 dupe;
1022a85fe12eSEd Maste 
1023a85fe12eSEd Maste 	src = read_section(s, &srcsz);
1024a85fe12eSEd Maste 	if (src == NULL || srcsz == 0) {
1025a85fe12eSEd Maste 		/* For empty section, we proceed if we need to append. */
1026a85fe12eSEd Maste 		if (!is_append_section(ecp, s->name))
1027a85fe12eSEd Maste 			return;
1028a85fe12eSEd Maste 	}
1029a85fe12eSEd Maste 
1030a85fe12eSEd Maste 	/* Allocate buffer needed for new section data. */
1031a85fe12eSEd Maste 	dstsz = srcsz;
1032a85fe12eSEd Maste 	if (is_append_section(ecp, s->name)) {
1033a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
1034a85fe12eSEd Maste 		dstsz += strlen(sac->string) + 1;
1035a85fe12eSEd Maste 	}
1036a85fe12eSEd Maste 	if ((b = malloc(dstsz)) == NULL)
1037a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1038a85fe12eSEd Maste 	s->buf = b;
1039a85fe12eSEd Maste 
1040a85fe12eSEd Maste 	/* Compress section. */
1041a85fe12eSEd Maste 	p = 0;
1042a85fe12eSEd Maste 	if (is_compress_section(ecp, s->name)) {
1043a85fe12eSEd Maste 		end = src + srcsz;
1044a85fe12eSEd Maste 		for(c = src; c < end;) {
1045a85fe12eSEd Maste 			len = 0;
1046a85fe12eSEd Maste 			while(c + len < end && c[len] != '\0')
1047a85fe12eSEd Maste 				len++;
1048a85fe12eSEd Maste 			if (c + len == end) {
1049a85fe12eSEd Maste 				/* XXX should we warn here? */
1050a85fe12eSEd Maste 				strncpy(&b[p], c, len);
1051a85fe12eSEd Maste 				p += len;
1052a85fe12eSEd Maste 				break;
1053a85fe12eSEd Maste 			}
1054a85fe12eSEd Maste 			dupe = 0;
1055a85fe12eSEd Maste 			for (d = b; d < b + p; ) {
1056a85fe12eSEd Maste 				if (strcmp(d, c) == 0) {
1057a85fe12eSEd Maste 					dupe = 1;
1058a85fe12eSEd Maste 					break;
1059a85fe12eSEd Maste 				}
1060a85fe12eSEd Maste 				d += strlen(d) + 1;
1061a85fe12eSEd Maste 			}
1062a85fe12eSEd Maste 			if (!dupe) {
1063a85fe12eSEd Maste 				strncpy(&b[p], c, len);
1064a85fe12eSEd Maste 				b[p + len] = '\0';
1065a85fe12eSEd Maste 				p += len + 1;
1066a85fe12eSEd Maste 			}
1067a85fe12eSEd Maste 			c += len + 1;
1068a85fe12eSEd Maste 		}
1069a85fe12eSEd Maste 	} else {
1070a85fe12eSEd Maste 		memcpy(b, src, srcsz);
1071a85fe12eSEd Maste 		p += srcsz;
1072a85fe12eSEd Maste 	}
1073a85fe12eSEd Maste 
1074a85fe12eSEd Maste 	/* Append section. */
1075a85fe12eSEd Maste 	if (is_append_section(ecp, s->name)) {
1076a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
1077a85fe12eSEd Maste 		len = strlen(sac->string);
1078a85fe12eSEd Maste 		strncpy(&b[p], sac->string, len);
1079a85fe12eSEd Maste 		b[p + len] = '\0';
1080a85fe12eSEd Maste 		p += len + 1;
1081a85fe12eSEd Maste 	}
1082a85fe12eSEd Maste 
1083a85fe12eSEd Maste 	s->sz = p;
1084a85fe12eSEd Maste 	s->nocopy = 1;
1085a85fe12eSEd Maste }
1086a85fe12eSEd Maste 
1087a85fe12eSEd Maste static void
1088a85fe12eSEd Maste print_data(const char *d, size_t sz)
1089a85fe12eSEd Maste {
1090a85fe12eSEd Maste 	const char *c;
1091a85fe12eSEd Maste 
1092a85fe12eSEd Maste 	for (c = d; c < d + sz; c++) {
1093a85fe12eSEd Maste 		if (*c == '\0')
1094a85fe12eSEd Maste 			putchar('\n');
1095a85fe12eSEd Maste 		else
1096a85fe12eSEd Maste 			putchar(*c);
1097a85fe12eSEd Maste 	}
1098a85fe12eSEd Maste }
1099a85fe12eSEd Maste 
1100a85fe12eSEd Maste static void
1101a85fe12eSEd Maste print_section(struct section *s)
1102a85fe12eSEd Maste {
1103a85fe12eSEd Maste 	Elf_Data	*id;
1104a85fe12eSEd Maste 	int		 elferr;
1105a85fe12eSEd Maste 
1106a85fe12eSEd Maste 	if (s->buf != NULL && s->sz > 0) {
1107a85fe12eSEd Maste 		print_data(s->buf, s->sz);
1108a85fe12eSEd Maste 	} else {
1109a85fe12eSEd Maste 		id = NULL;
1110839529caSEd Maste 		while ((id = elf_getdata(s->is, id)) != NULL ||
1111839529caSEd Maste 		    (id = elf_rawdata(s->is, id)) != NULL) {
1112839529caSEd Maste 			(void) elf_errno();
1113a85fe12eSEd Maste 			print_data(id->d_buf, id->d_size);
1114839529caSEd Maste 		}
1115a85fe12eSEd Maste 		elferr = elf_errno();
1116a85fe12eSEd Maste 		if (elferr != 0)
1117a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1118a85fe12eSEd Maste 			    elf_errmsg(elferr));
1119a85fe12eSEd Maste 	}
1120a85fe12eSEd Maste 	putchar('\n');
1121a85fe12eSEd Maste }
1122a85fe12eSEd Maste 
1123a85fe12eSEd Maste static void *
1124a85fe12eSEd Maste read_section(struct section *s, size_t *size)
1125a85fe12eSEd Maste {
1126a85fe12eSEd Maste 	Elf_Data	*id;
1127a85fe12eSEd Maste 	char		*b;
1128a85fe12eSEd Maste 	size_t		 sz;
1129a85fe12eSEd Maste 	int		 elferr;
1130a85fe12eSEd Maste 
1131a85fe12eSEd Maste 	sz = 0;
1132a85fe12eSEd Maste 	b = NULL;
1133a85fe12eSEd Maste 	id = NULL;
1134839529caSEd Maste 	while ((id = elf_getdata(s->is, id)) != NULL ||
1135839529caSEd Maste 	    (id = elf_rawdata(s->is, id)) != NULL) {
1136839529caSEd Maste 		(void) elf_errno();
1137a85fe12eSEd Maste 		if (b == NULL)
1138a85fe12eSEd Maste 			b = malloc(id->d_size);
1139a85fe12eSEd Maste 		else
1140*f2530c80SMark Johnston 			b = realloc(b, sz + id->d_size);
1141a85fe12eSEd Maste 		if (b == NULL)
1142a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc or realloc failed");
1143a85fe12eSEd Maste 
1144a85fe12eSEd Maste 		memcpy(&b[sz], id->d_buf, id->d_size);
1145a85fe12eSEd Maste 		sz += id->d_size;
1146a85fe12eSEd Maste 	}
1147a85fe12eSEd Maste 	elferr = elf_errno();
1148a85fe12eSEd Maste 	if (elferr != 0)
1149a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1150a85fe12eSEd Maste 		    elf_errmsg(elferr));
1151a85fe12eSEd Maste 
1152a85fe12eSEd Maste 	*size = sz;
1153a85fe12eSEd Maste 
1154a85fe12eSEd Maste 	return (b);
1155a85fe12eSEd Maste }
1156a85fe12eSEd Maste 
1157a85fe12eSEd Maste void
1158a85fe12eSEd Maste copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy,
1159a85fe12eSEd Maste     int sec_flags)
1160a85fe12eSEd Maste {
1161a85fe12eSEd Maste 	GElf_Shdr ish, osh;
1162a85fe12eSEd Maste 
1163a85fe12eSEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
1164839529caSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1165a85fe12eSEd Maste 		    elf_errmsg(-1));
1166a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
1167839529caSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1168a85fe12eSEd Maste 		    elf_errmsg(-1));
1169a85fe12eSEd Maste 
1170a85fe12eSEd Maste 	if (copy)
1171a85fe12eSEd Maste 		(void) memcpy(&osh, &ish, sizeof(ish));
1172a85fe12eSEd Maste 	else {
1173a85fe12eSEd Maste 		osh.sh_type		= s->type;
1174a85fe12eSEd Maste 		osh.sh_addr		= s->vma;
1175a85fe12eSEd Maste 		osh.sh_offset		= s->off;
1176a85fe12eSEd Maste 		osh.sh_size		= s->sz;
1177a85fe12eSEd Maste 		osh.sh_link		= ish.sh_link;
1178a85fe12eSEd Maste 		osh.sh_info		= ish.sh_info;
1179a85fe12eSEd Maste 		osh.sh_addralign	= s->align;
1180a85fe12eSEd Maste 		osh.sh_entsize		= ish.sh_entsize;
1181a85fe12eSEd Maste 
1182a85fe12eSEd Maste 		if (sec_flags) {
1183a85fe12eSEd Maste 			osh.sh_flags = 0;
1184839529caSEd Maste 			if (sec_flags & SF_ALLOC)
1185a85fe12eSEd Maste 				osh.sh_flags |= SHF_ALLOC;
1186a85fe12eSEd Maste 			if ((sec_flags & SF_READONLY) == 0)
1187a85fe12eSEd Maste 				osh.sh_flags |= SHF_WRITE;
1188a85fe12eSEd Maste 			if (sec_flags & SF_CODE)
1189a85fe12eSEd Maste 				osh.sh_flags |= SHF_EXECINSTR;
1190839529caSEd Maste 			if ((sec_flags & SF_CONTENTS) &&
1191839529caSEd Maste 			    s->type == SHT_NOBITS && s->sz > 0) {
1192839529caSEd Maste 				/*
1193839529caSEd Maste 				 * Convert SHT_NOBITS section to section with
1194839529caSEd Maste 				 * (zero'ed) content on file.
1195839529caSEd Maste 				 */
1196839529caSEd Maste 				osh.sh_type = s->type = SHT_PROGBITS;
1197839529caSEd Maste 				if ((s->buf = calloc(1, s->sz)) == NULL)
1198839529caSEd Maste 					err(EXIT_FAILURE, "malloc failed");
1199839529caSEd Maste 				s->nocopy = 1;
1200839529caSEd Maste 			}
12013ef90571SEd Maste 		} else {
1202a85fe12eSEd Maste 			osh.sh_flags = ish.sh_flags;
1203839529caSEd Maste 			/*
1204839529caSEd Maste 			 * Newer binutils as(1) emits the section flag
1205839529caSEd Maste 			 * SHF_INFO_LINK for relocation sections. elfcopy
1206839529caSEd Maste 			 * emits this flag in the output section if it's
1207839529caSEd Maste 			 * missing in the input section, to remain compatible
1208839529caSEd Maste 			 * with binutils.
1209839529caSEd Maste 			 */
12103ef90571SEd Maste 			if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)
12113ef90571SEd Maste 				osh.sh_flags |= SHF_INFO_LINK;
12123ef90571SEd Maste 		}
1213a85fe12eSEd Maste 	}
1214a85fe12eSEd Maste 
1215a85fe12eSEd Maste 	if (name == NULL)
1216a85fe12eSEd Maste 		add_to_shstrtab(ecp, s->name);
1217a85fe12eSEd Maste 	else
1218a85fe12eSEd Maste 		add_to_shstrtab(ecp, name);
1219a85fe12eSEd Maste 
1220a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &osh))
1221a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
1222a85fe12eSEd Maste 		    elf_errmsg(-1));
1223a85fe12eSEd Maste }
1224a85fe12eSEd Maste 
1225a85fe12eSEd Maste void
1226a85fe12eSEd Maste copy_data(struct section *s)
1227a85fe12eSEd Maste {
1228a85fe12eSEd Maste 	Elf_Data	*id, *od;
1229a85fe12eSEd Maste 	int		 elferr;
1230a85fe12eSEd Maste 
1231a85fe12eSEd Maste 	if (s->nocopy && s->buf == NULL)
1232a85fe12eSEd Maste 		return;
1233a85fe12eSEd Maste 
1234a85fe12eSEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL) {
1235839529caSEd Maste 		(void) elf_errno();
1236839529caSEd Maste 		if ((id = elf_rawdata(s->is, NULL)) == NULL) {
1237a85fe12eSEd Maste 			elferr = elf_errno();
1238a85fe12eSEd Maste 			if (elferr != 0)
1239839529caSEd Maste 				errx(EXIT_FAILURE, "failed to read section:"
1240839529caSEd Maste 				    " %s", s->name);
1241a85fe12eSEd Maste 			return;
1242a85fe12eSEd Maste 		}
1243839529caSEd Maste 	}
1244a85fe12eSEd Maste 
1245a85fe12eSEd Maste 	if ((od = elf_newdata(s->os)) == NULL)
1246a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1247a85fe12eSEd Maste 		    elf_errmsg(-1));
1248a85fe12eSEd Maste 
1249a85fe12eSEd Maste 	if (s->nocopy) {
1250a85fe12eSEd Maste 		/* Use s->buf as content if s->nocopy is set. */
1251a85fe12eSEd Maste 		od->d_align	= id->d_align;
1252a85fe12eSEd Maste 		od->d_off	= 0;
1253a85fe12eSEd Maste 		od->d_buf	= s->buf;
1254a85fe12eSEd Maste 		od->d_type	= id->d_type;
1255a85fe12eSEd Maste 		od->d_size	= s->sz;
1256a85fe12eSEd Maste 		od->d_version	= id->d_version;
1257a85fe12eSEd Maste 	} else {
1258a85fe12eSEd Maste 		od->d_align	= id->d_align;
1259a85fe12eSEd Maste 		od->d_off	= id->d_off;
1260a85fe12eSEd Maste 		od->d_buf	= id->d_buf;
1261a85fe12eSEd Maste 		od->d_type	= id->d_type;
1262a85fe12eSEd Maste 		od->d_size	= id->d_size;
1263a85fe12eSEd Maste 		od->d_version	= id->d_version;
1264a85fe12eSEd Maste 	}
12654a85c691SEd Maste 
12664a85c691SEd Maste 	/*
12674a85c691SEd Maste 	 * Alignment Fixup. libelf does not allow the alignment for
12684a85c691SEd Maste 	 * Elf_Data descriptor to be set to 0. In this case we workaround
12694a85c691SEd Maste 	 * it by setting the alignment to 1.
12704a85c691SEd Maste 	 *
12714a85c691SEd Maste 	 * According to the ELF ABI, alignment 0 and 1 has the same
12724a85c691SEd Maste 	 * meaning: the section has no alignment constraints.
12734a85c691SEd Maste 	 */
12744a85c691SEd Maste 	if (od->d_align == 0)
12754a85c691SEd Maste 		od->d_align = 1;
1276a85fe12eSEd Maste }
1277a85fe12eSEd Maste 
1278a85fe12eSEd Maste struct section *
1279a85fe12eSEd Maste create_external_section(struct elfcopy *ecp, const char *name, char *newname,
1280a85fe12eSEd Maste     void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype,
1281a85fe12eSEd Maste     uint64_t flags, uint64_t align, uint64_t vma, int loadable)
1282a85fe12eSEd Maste {
1283a85fe12eSEd Maste 	struct section	*s;
1284a85fe12eSEd Maste 	Elf_Scn		*os;
1285a85fe12eSEd Maste 	Elf_Data	*od;
1286a85fe12eSEd Maste 	GElf_Shdr	 osh;
1287a85fe12eSEd Maste 
1288a85fe12eSEd Maste 	if ((os = elf_newscn(ecp->eout)) == NULL)
1289a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newscn() failed: %s",
1290a85fe12eSEd Maste 		    elf_errmsg(-1));
1291a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
1292a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
1293a85fe12eSEd Maste 	s->name = name;
1294a85fe12eSEd Maste 	s->newname = newname;	/* needs to be free()'ed */
1295a85fe12eSEd Maste 	s->off = off;
1296a85fe12eSEd Maste 	s->sz = size;
1297a85fe12eSEd Maste 	s->vma = vma;
1298a85fe12eSEd Maste 	s->align = align;
1299a85fe12eSEd Maste 	s->loadable = loadable;
1300a85fe12eSEd Maste 	s->is = NULL;
1301a85fe12eSEd Maste 	s->os = os;
1302a85fe12eSEd Maste 	s->type = stype;
1303a85fe12eSEd Maste 	s->nocopy = 1;
1304a85fe12eSEd Maste 	insert_to_sec_list(ecp, s, 1);
1305a85fe12eSEd Maste 
1306a85fe12eSEd Maste 	if (gelf_getshdr(os, &osh) == NULL)
1307a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1308a85fe12eSEd Maste 		    elf_errmsg(-1));
1309a85fe12eSEd Maste 	osh.sh_flags = flags;
1310a85fe12eSEd Maste 	osh.sh_type = s->type;
1311a85fe12eSEd Maste 	osh.sh_addr = s->vma;
1312a85fe12eSEd Maste 	osh.sh_addralign = s->align;
1313a85fe12eSEd Maste 	if (!gelf_update_shdr(os, &osh))
1314a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1315a85fe12eSEd Maste 		    elf_errmsg(-1));
1316a85fe12eSEd Maste 	add_to_shstrtab(ecp, name);
1317a85fe12eSEd Maste 
1318a85fe12eSEd Maste 	if (buf != NULL && size != 0) {
1319a85fe12eSEd Maste 		if ((od = elf_newdata(os)) == NULL)
1320a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1321a85fe12eSEd Maste 			    elf_errmsg(-1));
1322a85fe12eSEd Maste 		od->d_align = align;
1323a85fe12eSEd Maste 		od->d_off = 0;
1324a85fe12eSEd Maste 		od->d_buf = buf;
1325a85fe12eSEd Maste 		od->d_size = size;
1326a85fe12eSEd Maste 		od->d_type = dtype;
1327a85fe12eSEd Maste 		od->d_version = EV_CURRENT;
1328a85fe12eSEd Maste 	}
1329a85fe12eSEd Maste 
1330a85fe12eSEd Maste 	/*
1331a85fe12eSEd Maste 	 * Clear SYMTAB_INTACT, as we probably need to update/add new
1332a85fe12eSEd Maste 	 * STT_SECTION symbols into the symbol table.
1333a85fe12eSEd Maste 	 */
1334a85fe12eSEd Maste 	ecp->flags &= ~SYMTAB_INTACT;
1335a85fe12eSEd Maste 
1336a85fe12eSEd Maste 	return (s);
1337a85fe12eSEd Maste }
1338a85fe12eSEd Maste 
1339a85fe12eSEd Maste /*
1340a85fe12eSEd Maste  * Insert sections specified by --add-section to the end of section list.
1341a85fe12eSEd Maste  */
1342a85fe12eSEd Maste static void
1343a85fe12eSEd Maste insert_sections(struct elfcopy *ecp)
1344a85fe12eSEd Maste {
1345a85fe12eSEd Maste 	struct sec_add	*sa;
1346a85fe12eSEd Maste 	struct section	*s;
1347a85fe12eSEd Maste 	size_t		 off;
1348839529caSEd Maste 	uint64_t	 stype;
1349a85fe12eSEd Maste 
1350a85fe12eSEd Maste 	/* Put these sections in the end of current list. */
1351a85fe12eSEd Maste 	off = 0;
1352a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1353a85fe12eSEd Maste 		if (s->type != SHT_NOBITS && s->type != SHT_NULL)
1354a85fe12eSEd Maste 			off = s->off + s->sz;
1355a85fe12eSEd Maste 		else
1356a85fe12eSEd Maste 			off = s->off;
1357a85fe12eSEd Maste 	}
1358a85fe12eSEd Maste 
1359a85fe12eSEd Maste 	STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) {
1360a85fe12eSEd Maste 
1361a85fe12eSEd Maste 		/* TODO: Add section header vma/lma, flag changes here */
1362a85fe12eSEd Maste 
1363839529caSEd Maste 		/*
1364839529caSEd Maste 		 * The default section type for user added section is
1365839529caSEd Maste 		 * SHT_PROGBITS. If the section name match certain patterns,
1366839529caSEd Maste 		 * elfcopy will try to set a more appropriate section type.
1367839529caSEd Maste 		 * However, data type is always set to ELF_T_BYTE and no
1368839529caSEd Maste 		 * translation is performed by libelf.
1369839529caSEd Maste 		 */
1370839529caSEd Maste 		stype = SHT_PROGBITS;
1371839529caSEd Maste 		if (strcmp(sa->name, ".note") == 0 ||
1372839529caSEd Maste 		    strncmp(sa->name, ".note.", strlen(".note.")) == 0)
1373839529caSEd Maste 			stype = SHT_NOTE;
1374839529caSEd Maste 
1375a85fe12eSEd Maste 		(void) create_external_section(ecp, sa->name, NULL, sa->content,
1376839529caSEd Maste 		    sa->size, off, stype, ELF_T_BYTE, 0, 1, 0, 0);
1377a85fe12eSEd Maste 	}
1378a85fe12eSEd Maste }
1379a85fe12eSEd Maste 
1380a85fe12eSEd Maste void
1381a85fe12eSEd Maste add_to_shstrtab(struct elfcopy *ecp, const char *name)
1382a85fe12eSEd Maste {
1383a85fe12eSEd Maste 
1384bc589b72SMark Johnston 	if (elftc_string_table_insert(ecp->shstrtab->strtab, name) == 0)
1385bc589b72SMark Johnston 		errx(EXIT_FAILURE, "elftc_string_table_insert failed");
1386a85fe12eSEd Maste }
1387a85fe12eSEd Maste 
1388a85fe12eSEd Maste void
1389a85fe12eSEd Maste update_shdr(struct elfcopy *ecp, int update_link)
1390a85fe12eSEd Maste {
1391a85fe12eSEd Maste 	struct section	*s;
1392a85fe12eSEd Maste 	GElf_Shdr	 osh;
1393a85fe12eSEd Maste 	int		 elferr;
1394a85fe12eSEd Maste 
1395bc589b72SMark Johnston 	/* Finalize the section name string table (.shstrtab). */
1396bc589b72SMark Johnston 	set_shstrtab(ecp);
1397bc589b72SMark Johnston 
1398a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1399a85fe12eSEd Maste 		if (s->pseudo)
1400a85fe12eSEd Maste 			continue;
1401a85fe12eSEd Maste 
1402a85fe12eSEd Maste 		if (gelf_getshdr(s->os, &osh) == NULL)
1403839529caSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
1404a85fe12eSEd Maste 			    elf_errmsg(-1));
1405a85fe12eSEd Maste 
1406a85fe12eSEd Maste 		/* Find section name in string table and set sh_name. */
1407bc589b72SMark Johnston 		osh.sh_name = elftc_string_table_lookup(ecp->shstrtab->strtab,
1408bc589b72SMark Johnston 		    s->name);
1409a85fe12eSEd Maste 
1410a85fe12eSEd Maste 		/*
1411a85fe12eSEd Maste 		 * sh_link needs to be updated, since the index of the
1412a85fe12eSEd Maste 		 * linked section might have changed.
1413a85fe12eSEd Maste 		 */
1414a85fe12eSEd Maste 		if (update_link && osh.sh_link != 0)
1415a85fe12eSEd Maste 			osh.sh_link = ecp->secndx[osh.sh_link];
1416a85fe12eSEd Maste 
1417a85fe12eSEd Maste 		/*
1418a85fe12eSEd Maste 		 * sh_info of relocation section links to the section to which
1419a85fe12eSEd Maste 		 * its relocation info applies. So it may need update as well.
1420a85fe12eSEd Maste 		 */
1421a85fe12eSEd Maste 		if ((s->type == SHT_REL || s->type == SHT_RELA) &&
1422a85fe12eSEd Maste 		    osh.sh_info != 0)
1423a85fe12eSEd Maste 			osh.sh_info = ecp->secndx[osh.sh_info];
1424a85fe12eSEd Maste 
1425b00fe64fSEd Maste 		/*
1426b00fe64fSEd Maste 		 * sh_info of SHT_GROUP section needs to point to the correct
1427b00fe64fSEd Maste 		 * string in the symbol table.
1428b00fe64fSEd Maste 		 */
1429b00fe64fSEd Maste 		if (s->type == SHT_GROUP && (ecp->flags & SYMTAB_EXIST) &&
1430b00fe64fSEd Maste 		    (ecp->flags & SYMTAB_INTACT) == 0)
1431b00fe64fSEd Maste 			osh.sh_info = ecp->symndx[osh.sh_info];
1432b00fe64fSEd Maste 
1433a85fe12eSEd Maste 		if (!gelf_update_shdr(s->os, &osh))
1434a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1435a85fe12eSEd Maste 			    elf_errmsg(-1));
1436a85fe12eSEd Maste 	}
1437a85fe12eSEd Maste 	elferr = elf_errno();
1438a85fe12eSEd Maste 	if (elferr != 0)
1439a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
1440a85fe12eSEd Maste 		    elf_errmsg(elferr));
1441a85fe12eSEd Maste }
1442a85fe12eSEd Maste 
1443a85fe12eSEd Maste void
1444a85fe12eSEd Maste init_shstrtab(struct elfcopy *ecp)
1445a85fe12eSEd Maste {
1446c8b057f4SMark Johnston 	Elf_Scn *shstrtab;
1447c8b057f4SMark Johnston 	GElf_Shdr shdr;
1448a85fe12eSEd Maste 	struct section *s;
1449c8b057f4SMark Johnston 	size_t indx, sizehint;
1450c8b057f4SMark Johnston 
14510070b575SMark Johnston 	if (elf_getshdrstrndx(ecp->ein, &indx) == 0) {
1452c8b057f4SMark Johnston 		shstrtab = elf_getscn(ecp->ein, indx);
1453c8b057f4SMark Johnston 		if (shstrtab == NULL)
1454c8b057f4SMark Johnston 			errx(EXIT_FAILURE, "elf_getscn failed: %s",
1455c8b057f4SMark Johnston 			    elf_errmsg(-1));
1456c8b057f4SMark Johnston 		if (gelf_getshdr(shstrtab, &shdr) != &shdr)
1457c8b057f4SMark Johnston 			errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
1458c8b057f4SMark Johnston 			    elf_errmsg(-1));
1459c8b057f4SMark Johnston 		sizehint = shdr.sh_size;
1460c8b057f4SMark Johnston 	} else {
14610070b575SMark Johnston 		/* Clear the error from elf_getshdrstrndx(3). */
14620070b575SMark Johnston 		(void)elf_errno();
1463c8b057f4SMark Johnston 		sizehint = 0;
1464c8b057f4SMark Johnston 	}
1465a85fe12eSEd Maste 
1466a85fe12eSEd Maste 	if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL)
1467a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
1468a85fe12eSEd Maste 	s = ecp->shstrtab;
1469a85fe12eSEd Maste 	s->name = ".shstrtab";
1470a85fe12eSEd Maste 	s->is = NULL;
1471a85fe12eSEd Maste 	s->sz = 0;
1472a85fe12eSEd Maste 	s->align = 1;
1473a85fe12eSEd Maste 	s->loadable = 0;
1474a85fe12eSEd Maste 	s->type = SHT_STRTAB;
1475a85fe12eSEd Maste 	s->vma = 0;
1476c8b057f4SMark Johnston 	s->strtab = elftc_string_table_create(sizehint);
14779ef62fdbSEd Maste 
1478bc589b72SMark Johnston 	add_to_shstrtab(ecp, "");
1479bc589b72SMark Johnston 	add_to_shstrtab(ecp, ".symtab");
1480bc589b72SMark Johnston 	add_to_shstrtab(ecp, ".strtab");
1481bc589b72SMark Johnston 	add_to_shstrtab(ecp, ".shstrtab");
1482a85fe12eSEd Maste }
1483a85fe12eSEd Maste 
1484bc589b72SMark Johnston static void
1485a85fe12eSEd Maste set_shstrtab(struct elfcopy *ecp)
1486a85fe12eSEd Maste {
1487a85fe12eSEd Maste 	struct section	*s;
1488a85fe12eSEd Maste 	Elf_Data	*data;
1489a85fe12eSEd Maste 	GElf_Shdr	 sh;
1490bc589b72SMark Johnston 	const char	*image;
1491bc589b72SMark Johnston 	size_t		 sz;
1492a85fe12eSEd Maste 
1493a85fe12eSEd Maste 	s = ecp->shstrtab;
1494a85fe12eSEd Maste 
1495619ba3b4SEd Maste 	if (s->os == NULL) {
1496619ba3b4SEd Maste 		/* Input object does not contain .shstrtab section */
1497619ba3b4SEd Maste 		if ((s->os = elf_newscn(ecp->eout)) == NULL)
1498619ba3b4SEd Maste 			errx(EXIT_FAILURE, "elf_newscn failed: %s",
1499619ba3b4SEd Maste 			    elf_errmsg(-1));
1500619ba3b4SEd Maste 		insert_to_sec_list(ecp, s, 1);
1501619ba3b4SEd Maste 	}
1502619ba3b4SEd Maste 
1503a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &sh) == NULL)
1504839529caSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1505a85fe12eSEd Maste 		    elf_errmsg(-1));
1506a85fe12eSEd Maste 	sh.sh_addr	= 0;
1507a85fe12eSEd Maste 	sh.sh_addralign	= 1;
1508a85fe12eSEd Maste 	sh.sh_offset	= s->off;
1509a85fe12eSEd Maste 	sh.sh_type	= SHT_STRTAB;
1510a85fe12eSEd Maste 	sh.sh_flags	= 0;
1511a85fe12eSEd Maste 	sh.sh_entsize	= 0;
1512a85fe12eSEd Maste 	sh.sh_info	= 0;
1513a85fe12eSEd Maste 	sh.sh_link	= 0;
1514a85fe12eSEd Maste 
1515a85fe12eSEd Maste 	if ((data = elf_newdata(s->os)) == NULL)
1516a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1517a85fe12eSEd Maste 		    elf_errmsg(-1));
1518a85fe12eSEd Maste 
1519a85fe12eSEd Maste 	/*
1520a85fe12eSEd Maste 	 * If we don't have a symbol table, skip those a few bytes
1521a85fe12eSEd Maste 	 * which are reserved for this in the beginning of shstrtab.
1522a85fe12eSEd Maste 	 */
1523a85fe12eSEd Maste 	if (!(ecp->flags & SYMTAB_EXIST)) {
1524bc589b72SMark Johnston 		elftc_string_table_remove(s->strtab, ".symtab");
1525bc589b72SMark Johnston 		elftc_string_table_remove(s->strtab, ".strtab");
1526a85fe12eSEd Maste 	}
1527a85fe12eSEd Maste 
1528bc589b72SMark Johnston 	image = elftc_string_table_image(s->strtab, &sz);
1529bc589b72SMark Johnston 	s->sz = sz;
1530bc589b72SMark Johnston 
1531bc589b72SMark Johnston 	sh.sh_size	= sz;
1532a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &sh))
1533a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1534a85fe12eSEd Maste 		    elf_errmsg(-1));
1535a85fe12eSEd Maste 
1536a85fe12eSEd Maste 	data->d_align	= 1;
1537bc589b72SMark Johnston 	data->d_buf	= (void *)(uintptr_t)image;
1538bc589b72SMark Johnston 	data->d_size	= sz;
1539a85fe12eSEd Maste 	data->d_off	= 0;
1540a85fe12eSEd Maste 	data->d_type	= ELF_T_BYTE;
1541a85fe12eSEd Maste 	data->d_version	= EV_CURRENT;
1542a85fe12eSEd Maste 
1543a85fe12eSEd Maste 	if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os)))
1544a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s",
1545a85fe12eSEd Maste 		     elf_errmsg(-1));
1546a85fe12eSEd Maste }
1547a85fe12eSEd Maste 
1548a85fe12eSEd Maste void
1549a85fe12eSEd Maste add_section(struct elfcopy *ecp, const char *arg)
1550a85fe12eSEd Maste {
1551a85fe12eSEd Maste 	struct sec_add	*sa;
1552a85fe12eSEd Maste 	struct stat	 sb;
1553a85fe12eSEd Maste 	const char	*s, *fn;
1554a85fe12eSEd Maste 	FILE		*fp;
1555a85fe12eSEd Maste 	int		 len;
1556a85fe12eSEd Maste 
1557a85fe12eSEd Maste 	if ((s = strchr(arg, '=')) == NULL)
1558a85fe12eSEd Maste 		errx(EXIT_FAILURE,
1559a85fe12eSEd Maste 		    "illegal format for --add-section option");
1560a85fe12eSEd Maste 	if ((sa = malloc(sizeof(*sa))) == NULL)
1561a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1562a85fe12eSEd Maste 
1563a85fe12eSEd Maste 	len = s - arg;
1564a85fe12eSEd Maste 	if ((sa->name = malloc(len + 1)) == NULL)
1565a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1566a85fe12eSEd Maste 	strncpy(sa->name, arg, len);
1567a85fe12eSEd Maste 	sa->name[len] = '\0';
1568a85fe12eSEd Maste 
1569a85fe12eSEd Maste 	fn = s + 1;
1570a85fe12eSEd Maste 	if (stat(fn, &sb) == -1)
1571a85fe12eSEd Maste 		err(EXIT_FAILURE, "stat failed");
1572a85fe12eSEd Maste 	sa->size = sb.st_size;
1573839529caSEd Maste 	if (sa->size > 0) {
1574a85fe12eSEd Maste 		if ((sa->content = malloc(sa->size)) == NULL)
1575a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
1576a85fe12eSEd Maste 		if ((fp = fopen(fn, "r")) == NULL)
1577a85fe12eSEd Maste 			err(EXIT_FAILURE, "can not open %s", fn);
1578a85fe12eSEd Maste 		if (fread(sa->content, 1, sa->size, fp) == 0 ||
1579a85fe12eSEd Maste 		    ferror(fp))
1580a85fe12eSEd Maste 			err(EXIT_FAILURE, "fread failed");
1581a85fe12eSEd Maste 		fclose(fp);
1582839529caSEd Maste 	} else
1583839529caSEd Maste 		sa->content = NULL;
1584a85fe12eSEd Maste 
1585a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1586a85fe12eSEd Maste 	ecp->flags |= SEC_ADD;
1587a85fe12eSEd Maste }
1588a85fe12eSEd Maste 
1589a85fe12eSEd Maste void
1590a85fe12eSEd Maste free_sec_add(struct elfcopy *ecp)
1591a85fe12eSEd Maste {
1592a85fe12eSEd Maste 	struct sec_add *sa, *sa_temp;
1593a85fe12eSEd Maste 
1594a85fe12eSEd Maste 	STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) {
1595a85fe12eSEd Maste 		STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list);
1596a85fe12eSEd Maste 		free(sa->name);
1597a85fe12eSEd Maste 		free(sa->content);
1598a85fe12eSEd Maste 		free(sa);
1599a85fe12eSEd Maste 	}
1600a85fe12eSEd Maste }
1601a85fe12eSEd Maste 
1602a85fe12eSEd Maste static void
1603a85fe12eSEd Maste add_gnu_debuglink(struct elfcopy *ecp)
1604a85fe12eSEd Maste {
1605a85fe12eSEd Maste 	struct sec_add	*sa;
1606a85fe12eSEd Maste 	struct stat	 sb;
1607a85fe12eSEd Maste 	FILE		*fp;
1608a85fe12eSEd Maste 	char		*fnbase, *buf;
1609a85fe12eSEd Maste 	int		 crc_off;
1610a85fe12eSEd Maste 	int		 crc;
1611a85fe12eSEd Maste 
1612a85fe12eSEd Maste 	if (ecp->debuglink == NULL)
1613a85fe12eSEd Maste 		return;
1614a85fe12eSEd Maste 
1615a85fe12eSEd Maste 	/* Read debug file content. */
1616a85fe12eSEd Maste 	if ((sa = malloc(sizeof(*sa))) == NULL)
1617a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1618a85fe12eSEd Maste 	if ((sa->name = strdup(".gnu_debuglink")) == NULL)
1619a85fe12eSEd Maste 		err(EXIT_FAILURE, "strdup failed");
1620a85fe12eSEd Maste 	if (stat(ecp->debuglink, &sb) == -1)
1621a85fe12eSEd Maste 		err(EXIT_FAILURE, "stat failed");
1622f5e9c916SEd Maste 	if (sb.st_size == 0)
1623f5e9c916SEd Maste 		errx(EXIT_FAILURE, "empty debug link target %s",
1624f5e9c916SEd Maste 		    ecp->debuglink);
1625a85fe12eSEd Maste 	if ((buf = malloc(sb.st_size)) == NULL)
1626a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1627a85fe12eSEd Maste 	if ((fp = fopen(ecp->debuglink, "r")) == NULL)
1628a85fe12eSEd Maste 		err(EXIT_FAILURE, "can not open %s", ecp->debuglink);
1629a85fe12eSEd Maste 	if (fread(buf, 1, sb.st_size, fp) == 0 ||
1630a85fe12eSEd Maste 	    ferror(fp))
1631a85fe12eSEd Maste 		err(EXIT_FAILURE, "fread failed");
1632a85fe12eSEd Maste 	fclose(fp);
1633a85fe12eSEd Maste 
1634a85fe12eSEd Maste 	/* Calculate crc checksum.  */
1635a85fe12eSEd Maste 	crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF);
1636a85fe12eSEd Maste 	free(buf);
1637a85fe12eSEd Maste 
1638a85fe12eSEd Maste 	/* Calculate section size and the offset to store crc checksum. */
1639a85fe12eSEd Maste 	if ((fnbase = basename(ecp->debuglink)) == NULL)
1640a85fe12eSEd Maste 		err(EXIT_FAILURE, "basename failed");
1641a85fe12eSEd Maste 	crc_off = roundup(strlen(fnbase) + 1, 4);
1642a85fe12eSEd Maste 	sa->size = crc_off + 4;
1643a85fe12eSEd Maste 
1644a85fe12eSEd Maste 	/* Section content. */
1645a85fe12eSEd Maste 	if ((sa->content = calloc(1, sa->size)) == NULL)
1646a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1647a85fe12eSEd Maste 	strncpy(sa->content, fnbase, strlen(fnbase));
1648a85fe12eSEd Maste 	if (ecp->oed == ELFDATA2LSB) {
1649a85fe12eSEd Maste 		sa->content[crc_off] = crc & 0xFF;
1650a85fe12eSEd Maste 		sa->content[crc_off + 1] = (crc >> 8) & 0xFF;
1651a85fe12eSEd Maste 		sa->content[crc_off + 2] = (crc >> 16) & 0xFF;
1652a85fe12eSEd Maste 		sa->content[crc_off + 3] = crc >> 24;
1653a85fe12eSEd Maste 	} else {
1654a85fe12eSEd Maste 		sa->content[crc_off] = crc >> 24;
1655a85fe12eSEd Maste 		sa->content[crc_off + 1] = (crc >> 16) & 0xFF;
1656a85fe12eSEd Maste 		sa->content[crc_off + 2] = (crc >> 8) & 0xFF;
1657a85fe12eSEd Maste 		sa->content[crc_off + 3] = crc & 0xFF;
1658a85fe12eSEd Maste 	}
1659a85fe12eSEd Maste 
1660a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1661a85fe12eSEd Maste 	ecp->flags |= SEC_ADD;
1662a85fe12eSEd Maste }
1663a85fe12eSEd Maste 
1664a85fe12eSEd Maste static uint32_t crctable[256] =
1665a85fe12eSEd Maste {
1666a85fe12eSEd Maste 	0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
1667a85fe12eSEd Maste 	0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
1668a85fe12eSEd Maste 	0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
1669a85fe12eSEd Maste 	0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
1670a85fe12eSEd Maste 	0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
1671a85fe12eSEd Maste 	0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
1672a85fe12eSEd Maste 	0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
1673a85fe12eSEd Maste 	0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
1674a85fe12eSEd Maste 	0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
1675a85fe12eSEd Maste 	0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
1676a85fe12eSEd Maste 	0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
1677a85fe12eSEd Maste 	0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
1678a85fe12eSEd Maste 	0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
1679a85fe12eSEd Maste 	0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
1680a85fe12eSEd Maste 	0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
1681a85fe12eSEd Maste 	0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
1682a85fe12eSEd Maste 	0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
1683a85fe12eSEd Maste 	0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
1684a85fe12eSEd Maste 	0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
1685a85fe12eSEd Maste 	0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
1686a85fe12eSEd Maste 	0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
1687a85fe12eSEd Maste 	0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
1688a85fe12eSEd Maste 	0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
1689a85fe12eSEd Maste 	0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
1690a85fe12eSEd Maste 	0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
1691a85fe12eSEd Maste 	0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
1692a85fe12eSEd Maste 	0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
1693a85fe12eSEd Maste 	0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
1694a85fe12eSEd Maste 	0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
1695a85fe12eSEd Maste 	0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
1696a85fe12eSEd Maste 	0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
1697a85fe12eSEd Maste 	0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
1698a85fe12eSEd Maste 	0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
1699a85fe12eSEd Maste 	0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
1700a85fe12eSEd Maste 	0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
1701a85fe12eSEd Maste 	0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
1702a85fe12eSEd Maste 	0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
1703a85fe12eSEd Maste 	0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
1704a85fe12eSEd Maste 	0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
1705a85fe12eSEd Maste 	0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
1706a85fe12eSEd Maste 	0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
1707a85fe12eSEd Maste 	0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
1708a85fe12eSEd Maste 	0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
1709a85fe12eSEd Maste 	0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
1710a85fe12eSEd Maste 	0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
1711a85fe12eSEd Maste 	0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
1712a85fe12eSEd Maste 	0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
1713a85fe12eSEd Maste 	0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
1714a85fe12eSEd Maste 	0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
1715a85fe12eSEd Maste 	0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
1716a85fe12eSEd Maste 	0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
1717a85fe12eSEd Maste 	0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
1718a85fe12eSEd Maste 	0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
1719a85fe12eSEd Maste 	0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
1720a85fe12eSEd Maste 	0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
1721a85fe12eSEd Maste 	0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
1722a85fe12eSEd Maste 	0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
1723a85fe12eSEd Maste 	0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
1724a85fe12eSEd Maste 	0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
1725a85fe12eSEd Maste 	0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
1726a85fe12eSEd Maste 	0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
1727a85fe12eSEd Maste 	0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
1728a85fe12eSEd Maste 	0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
1729a85fe12eSEd Maste 	0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
1730a85fe12eSEd Maste };
1731a85fe12eSEd Maste 
1732a85fe12eSEd Maste static uint32_t
1733a85fe12eSEd Maste calc_crc32(const char *p, size_t len, uint32_t crc)
1734a85fe12eSEd Maste {
1735a85fe12eSEd Maste 	uint32_t i;
1736a85fe12eSEd Maste 
1737a85fe12eSEd Maste 	for (i = 0; i < len; i++) {
1738a85fe12eSEd Maste 		crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);
1739a85fe12eSEd Maste 	}
1740a85fe12eSEd Maste 
1741a85fe12eSEd Maste 	return (crc ^ 0xFFFFFFFF);
1742a85fe12eSEd Maste }
1743