xref: /freebsd/contrib/elftoolchain/elfcopy/segments.c (revision 50f69bfbd6ffaf716d0822c0e47354c3319a83c2)
1a85fe12eSEd Maste /*-
2a85fe12eSEd Maste  * Copyright (c) 2007-2010,2012 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/cdefs.h>
28a85fe12eSEd Maste #include <sys/queue.h>
29a85fe12eSEd Maste #include <err.h>
30a85fe12eSEd Maste #include <gelf.h>
31*50f69bfbSEd Maste #include <stdint.h>
32a85fe12eSEd Maste #include <stdio.h>
33a85fe12eSEd Maste #include <stdlib.h>
34a85fe12eSEd Maste #include <string.h>
35a85fe12eSEd Maste 
36a85fe12eSEd Maste #include "elfcopy.h"
37a85fe12eSEd Maste 
38a85fe12eSEd Maste ELFTC_VCSID("$Id: segments.c 2542 2012-08-12 16:14:15Z kaiwang27 $");
39a85fe12eSEd Maste 
40a85fe12eSEd Maste static void	insert_to_inseg_list(struct segment *seg, struct section *sec);
41a85fe12eSEd Maste 
42a85fe12eSEd Maste /*
43a85fe12eSEd Maste  * elfcopy's segment handling is relatively simpler and less powerful than
44a85fe12eSEd Maste  * libbfd. Program headers are modified or copied from input to output objects,
45a85fe12eSEd Maste  * but never re-generated. As a result, if the input object has incorrect
46a85fe12eSEd Maste  * program headers, the output object's program headers will remain incorrect
47a85fe12eSEd Maste  * or become even worse.
48a85fe12eSEd Maste  */
49a85fe12eSEd Maste 
50a85fe12eSEd Maste /*
51a85fe12eSEd Maste  * Check whether a section is "loadable". If so, add it to the
52a85fe12eSEd Maste  * corresponding segment list(s) and return 1.
53a85fe12eSEd Maste  */
54a85fe12eSEd Maste int
55a85fe12eSEd Maste add_to_inseg_list(struct elfcopy *ecp, struct section *s)
56a85fe12eSEd Maste {
57a85fe12eSEd Maste 	struct segment	*seg;
58a85fe12eSEd Maste 	int		 loadable;
59a85fe12eSEd Maste 
60a85fe12eSEd Maste 	if (ecp->ophnum == 0)
61a85fe12eSEd Maste 		return (0);
62a85fe12eSEd Maste 
63a85fe12eSEd Maste 	/*
64a85fe12eSEd Maste 	 * Segment is a different view of an ELF object. One segment can
65a85fe12eSEd Maste 	 * contain one or more sections, and one section can be included
66a85fe12eSEd Maste 	 * in one or more segments, or not included in any segment at all.
67a85fe12eSEd Maste 	 * We call those sections which can be found in one or more segments
68a85fe12eSEd Maste 	 * "loadable" sections, and call the rest "unloadable" sections.
69a85fe12eSEd Maste 	 * We keep track of "loadable" sections in their containing
70a85fe12eSEd Maste 	 * segment(s)' v_sec queue. These information are later used to
71a85fe12eSEd Maste 	 * recalculate the extents of segments, when sections are removed,
72a85fe12eSEd Maste 	 * for example.
73a85fe12eSEd Maste 	 */
74a85fe12eSEd Maste 	loadable = 0;
75a85fe12eSEd Maste 	STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
76a85fe12eSEd Maste 		if (s->off < seg->off)
77a85fe12eSEd Maste 			continue;
78a85fe12eSEd Maste 		if (s->off + s->sz > seg->off + seg->fsz &&
79a85fe12eSEd Maste 		    s->type != SHT_NOBITS)
80a85fe12eSEd Maste 			continue;
81a85fe12eSEd Maste 		if (s->off + s->sz > seg->off + seg->msz)
82a85fe12eSEd Maste 			continue;
83a85fe12eSEd Maste 
84a85fe12eSEd Maste 		insert_to_inseg_list(seg, s);
85a85fe12eSEd Maste 		if (seg->type == PT_LOAD)
86a85fe12eSEd Maste 			s->seg = seg;
87a85fe12eSEd Maste 		s->lma = seg->addr + (s->off - seg->off);
88a85fe12eSEd Maste 		loadable = 1;
89a85fe12eSEd Maste 	}
90a85fe12eSEd Maste 
91a85fe12eSEd Maste 	return (loadable);
92a85fe12eSEd Maste }
93a85fe12eSEd Maste 
94a85fe12eSEd Maste void
95a85fe12eSEd Maste adjust_addr(struct elfcopy *ecp)
96a85fe12eSEd Maste {
97a85fe12eSEd Maste 	struct section *s, *s0;
98a85fe12eSEd Maste 	struct segment *seg;
99a85fe12eSEd Maste 	struct sec_action *sac;
100a85fe12eSEd Maste 	uint64_t dl, lma, old_vma, start, end;
101a85fe12eSEd Maste 	int found, i;
102a85fe12eSEd Maste 
103a85fe12eSEd Maste 	/*
104a85fe12eSEd Maste 	 * Apply VMA and global LMA changes in the first iteration.
105a85fe12eSEd Maste 	 */
106a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
107a85fe12eSEd Maste 
108a85fe12eSEd Maste 		/* Only adjust loadable section's address. */
109a85fe12eSEd Maste 		if (!s->loadable || s->seg == NULL)
110a85fe12eSEd Maste 			continue;
111a85fe12eSEd Maste 
112a85fe12eSEd Maste 		/* Apply global LMA adjustment. */
113a85fe12eSEd Maste 		if (ecp->change_addr != 0)
114a85fe12eSEd Maste 			s->lma += ecp->change_addr;
115a85fe12eSEd Maste 
116a85fe12eSEd Maste 		if (!s->pseudo) {
117a85fe12eSEd Maste 			old_vma = s->vma;
118a85fe12eSEd Maste 
119a85fe12eSEd Maste 			/* Apply global VMA adjustment. */
120a85fe12eSEd Maste 			if (ecp->change_addr != 0)
121a85fe12eSEd Maste 				s->vma += ecp->change_addr;
122a85fe12eSEd Maste 
123a85fe12eSEd Maste 			/* Apply section VMA adjustment. */
124a85fe12eSEd Maste 			sac = lookup_sec_act(ecp, s->name, 0);
125a85fe12eSEd Maste 			if (sac == NULL)
126a85fe12eSEd Maste 				continue;
127a85fe12eSEd Maste 			if (sac->setvma)
128a85fe12eSEd Maste 				s->vma = sac->vma;
129a85fe12eSEd Maste 			if (sac->vma_adjust != 0)
130a85fe12eSEd Maste 				s->vma += sac->vma_adjust;
131a85fe12eSEd Maste 		}
132a85fe12eSEd Maste 	}
133a85fe12eSEd Maste 
134a85fe12eSEd Maste 	/*
135a85fe12eSEd Maste 	 * Apply sections LMA change in the second iteration.
136a85fe12eSEd Maste 	 */
137a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
138a85fe12eSEd Maste 
139a85fe12eSEd Maste 		/* Only adjust loadable section's LMA. */
140a85fe12eSEd Maste 		if (!s->loadable || s->seg == NULL)
141a85fe12eSEd Maste 			continue;
142a85fe12eSEd Maste 
143a85fe12eSEd Maste 		/*
144a85fe12eSEd Maste 		 * Check if there is a LMA change request for this
145a85fe12eSEd Maste 		 * section.
146a85fe12eSEd Maste 		 */
147a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
148a85fe12eSEd Maste 		if (sac == NULL)
149a85fe12eSEd Maste 			continue;
150a85fe12eSEd Maste 		if (!sac->setlma && sac->lma_adjust == 0)
151a85fe12eSEd Maste 			continue;
152a85fe12eSEd Maste 		lma = s->lma;
153a85fe12eSEd Maste 		if (sac->setlma)
154a85fe12eSEd Maste 			lma = sac->lma;
155a85fe12eSEd Maste 		if (sac->lma_adjust != 0)
156a85fe12eSEd Maste 			lma += sac->lma_adjust;
157a85fe12eSEd Maste 		if (lma == s->lma)
158a85fe12eSEd Maste 			continue;
159a85fe12eSEd Maste 
160a85fe12eSEd Maste 		/*
161a85fe12eSEd Maste 		 * Check if the LMA change is viable.
162a85fe12eSEd Maste 		 *
163a85fe12eSEd Maste 		 * 1. Check if the new LMA is properly aligned accroding to
164a85fe12eSEd Maste 		 *    section alignment.
165a85fe12eSEd Maste 		 *
166a85fe12eSEd Maste 		 * 2. Compute the new extent of segment that contains this
167a85fe12eSEd Maste 		 *    section, make sure it doesn't overlap with other
168a85fe12eSEd Maste 		 *    segments.
169a85fe12eSEd Maste 		 */
170a85fe12eSEd Maste #ifdef	DEBUG
171a85fe12eSEd Maste 		printf("LMA for section %s: %#jx\n", s->name, lma);
172a85fe12eSEd Maste #endif
173a85fe12eSEd Maste 
174a85fe12eSEd Maste 		if (lma % s->align != 0)
175a85fe12eSEd Maste 			errx(EXIT_FAILURE, "The load address %#jx for "
176a85fe12eSEd Maste 			    "section %s is not aligned to %ju",
177a85fe12eSEd Maste 			    (uintmax_t) lma, s->name, s->align);
178a85fe12eSEd Maste 
179a85fe12eSEd Maste 		if (lma < s->lma) {
180a85fe12eSEd Maste 			/* Move section to lower address. */
181a85fe12eSEd Maste 			if (lma < s->lma - s->seg->addr)
182a85fe12eSEd Maste 				errx(EXIT_FAILURE, "Not enough space to move "
183a85fe12eSEd Maste 				    "section %s load address to %#jx", s->name,
184a85fe12eSEd Maste 				    (uintmax_t) lma);
185a85fe12eSEd Maste 			start = lma - (s->lma - s->seg->addr);
186a85fe12eSEd Maste 			if (s == s->seg->v_sec[s->seg->nsec - 1])
187a85fe12eSEd Maste 				end = start + s->seg->msz;
188a85fe12eSEd Maste 			else
189a85fe12eSEd Maste 				end = s->seg->addr + s->seg->msz;
190a85fe12eSEd Maste 
191a85fe12eSEd Maste 		} else {
192a85fe12eSEd Maste 			/* Move section to upper address. */
193a85fe12eSEd Maste 			if (s == s->seg->v_sec[0])
194a85fe12eSEd Maste 				start = lma;
195a85fe12eSEd Maste 			else
196a85fe12eSEd Maste 				start = s->seg->addr;
197a85fe12eSEd Maste 			end = lma + (s->seg->addr + s->seg->msz - s->lma);
198a85fe12eSEd Maste 			if (end < start)
199a85fe12eSEd Maste 				errx(EXIT_FAILURE, "Not enough space to move "
200a85fe12eSEd Maste 				    "section %s load address to %#jx", s->name,
201a85fe12eSEd Maste 				    (uintmax_t) lma);
202a85fe12eSEd Maste 		}
203a85fe12eSEd Maste 
204a85fe12eSEd Maste #ifdef	DEBUG
205a85fe12eSEd Maste 		printf("new extent for segment containing %s: (%#jx,%#jx)\n",
206a85fe12eSEd Maste 		    s->name, start, end);
207a85fe12eSEd Maste #endif
208a85fe12eSEd Maste 
209a85fe12eSEd Maste 		STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
210a85fe12eSEd Maste 			if (seg == s->seg || seg->type != PT_LOAD)
211a85fe12eSEd Maste 				continue;
212a85fe12eSEd Maste 			if (start > seg->addr + seg->msz)
213a85fe12eSEd Maste 				continue;
214a85fe12eSEd Maste 			if (end < seg->addr)
215a85fe12eSEd Maste 				continue;
216a85fe12eSEd Maste 			errx(EXIT_FAILURE, "The extent of segment containing "
217a85fe12eSEd Maste 			    "section %s overlaps with segment(%#jx,%#jx)",
218a85fe12eSEd Maste 			    s->name, seg->addr, seg->addr + seg->msz);
219a85fe12eSEd Maste 		}
220a85fe12eSEd Maste 
221a85fe12eSEd Maste 		/*
222a85fe12eSEd Maste 		 * Update section LMA and file offset.
223a85fe12eSEd Maste 		 */
224a85fe12eSEd Maste 
225a85fe12eSEd Maste 		if (lma < s->lma) {
226a85fe12eSEd Maste 			/*
227a85fe12eSEd Maste 			 * To move a section to lower load address, we decrease
228a85fe12eSEd Maste 			 * the load addresses of the section and all the
229a85fe12eSEd Maste 			 * sections that are before it, and we increase the
230a85fe12eSEd Maste 			 * file offsets of all the sections that are after it.
231a85fe12eSEd Maste 			 */
232a85fe12eSEd Maste 			dl = s->lma - lma;
233a85fe12eSEd Maste 			for (i = 0; i < s->seg->nsec; i++) {
234a85fe12eSEd Maste 				s0 = s->seg->v_sec[i];
235a85fe12eSEd Maste 				s0->lma -= dl;
236a85fe12eSEd Maste #ifdef	DEBUG
237a85fe12eSEd Maste 				printf("section %s LMA set to %#jx\n",
238a85fe12eSEd Maste 				    s0->name, (uintmax_t) s0->lma);
239a85fe12eSEd Maste #endif
240a85fe12eSEd Maste 				if (s0 == s)
241a85fe12eSEd Maste 					break;
242a85fe12eSEd Maste 			}
243a85fe12eSEd Maste 			for (i = i + 1; i < s->seg->nsec; i++) {
244a85fe12eSEd Maste 				s0 = s->seg->v_sec[i];
245a85fe12eSEd Maste 				s0->off += dl;
246a85fe12eSEd Maste #ifdef	DEBUG
247a85fe12eSEd Maste 				printf("section %s offset set to %#jx\n",
248a85fe12eSEd Maste 				    s0->name, (uintmax_t) s0->off);
249a85fe12eSEd Maste #endif
250a85fe12eSEd Maste 			}
251a85fe12eSEd Maste 		} else {
252a85fe12eSEd Maste 			/*
253a85fe12eSEd Maste 			 * To move a section to upper load address, we increase
254a85fe12eSEd Maste 			 * the load addresses of the section and all the
255a85fe12eSEd Maste 			 * sections that are after it, and we increase the
256a85fe12eSEd Maste 			 * their file offsets too unless the section in question
257a85fe12eSEd Maste 			 * is the first in its containing segment.
258a85fe12eSEd Maste 			 */
259a85fe12eSEd Maste 			dl = lma - s->lma;
260a85fe12eSEd Maste 			for (i = 0; i < s->seg->nsec; i++)
261a85fe12eSEd Maste 				if (s->seg->v_sec[i] == s)
262a85fe12eSEd Maste 					break;
263a85fe12eSEd Maste 			if (i >= s->seg->nsec)
264a85fe12eSEd Maste 				errx(EXIT_FAILURE, "Internal: section `%s' not"
265a85fe12eSEd Maste 				    " found in its containing segement",
266a85fe12eSEd Maste 				    s->name);
267a85fe12eSEd Maste 			for (; i < s->seg->nsec; i++) {
268a85fe12eSEd Maste 				s0 = s->seg->v_sec[i];
269a85fe12eSEd Maste 				s0->lma += dl;
270a85fe12eSEd Maste #ifdef	DEBUG
271a85fe12eSEd Maste 				printf("section %s LMA set to %#jx\n",
272a85fe12eSEd Maste 				    s0->name, (uintmax_t) s0->lma);
273a85fe12eSEd Maste #endif
274a85fe12eSEd Maste 				if (s != s->seg->v_sec[0]) {
275a85fe12eSEd Maste 					s0->off += dl;
276a85fe12eSEd Maste #ifdef	DEBUG
277a85fe12eSEd Maste 					printf("section %s offset set to %#jx\n",
278a85fe12eSEd Maste 					    s0->name, (uintmax_t) s0->off);
279a85fe12eSEd Maste #endif
280a85fe12eSEd Maste 				}
281a85fe12eSEd Maste 			}
282a85fe12eSEd Maste 		}
283a85fe12eSEd Maste 	}
284a85fe12eSEd Maste 
285a85fe12eSEd Maste 	/*
286a85fe12eSEd Maste 	 * Apply load address padding.
287a85fe12eSEd Maste 	 */
288a85fe12eSEd Maste 
289a85fe12eSEd Maste 	if (ecp->pad_to != 0) {
290a85fe12eSEd Maste 
291a85fe12eSEd Maste 		/*
292a85fe12eSEd Maste 		 * Find the section with highest load address.
293a85fe12eSEd Maste 		 */
294a85fe12eSEd Maste 
295a85fe12eSEd Maste 		s = NULL;
296a85fe12eSEd Maste 		STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
297a85fe12eSEd Maste 			if (seg->type != PT_LOAD)
298a85fe12eSEd Maste 				continue;
299a85fe12eSEd Maste 			for (i = seg->nsec - 1; i >= 0; i--)
300a85fe12eSEd Maste 				if (seg->v_sec[i]->type != SHT_NOBITS)
301a85fe12eSEd Maste 					break;
302a85fe12eSEd Maste 			if (i < 0)
303a85fe12eSEd Maste 				continue;
304a85fe12eSEd Maste 			if (s == NULL)
305a85fe12eSEd Maste 				s = seg->v_sec[i];
306a85fe12eSEd Maste 			else {
307a85fe12eSEd Maste 				s0 = seg->v_sec[i];
308a85fe12eSEd Maste 				if (s0->lma > s->lma)
309a85fe12eSEd Maste 					s = s0;
310a85fe12eSEd Maste 			}
311a85fe12eSEd Maste 		}
312a85fe12eSEd Maste 
313a85fe12eSEd Maste 		if (s == NULL)
314a85fe12eSEd Maste 			goto issue_warn;
315a85fe12eSEd Maste 
316a85fe12eSEd Maste 		/* No need to pad if the pad_to address is lower. */
317a85fe12eSEd Maste 		if (ecp->pad_to <= s->lma + s->sz)
318a85fe12eSEd Maste 			goto issue_warn;
319a85fe12eSEd Maste 
320a85fe12eSEd Maste 		s->pad_sz = ecp->pad_to - (s->lma + s->sz);
321a85fe12eSEd Maste #ifdef	DEBUG
322a85fe12eSEd Maste 		printf("pad section %s load to address %#jx by %#jx\n", s->name,
323a85fe12eSEd Maste 		    (uintmax_t) ecp->pad_to, (uintmax_t) s->pad_sz);
324a85fe12eSEd Maste #endif
325a85fe12eSEd Maste 	}
326a85fe12eSEd Maste 
327a85fe12eSEd Maste issue_warn:
328a85fe12eSEd Maste 
329a85fe12eSEd Maste 	/*
330a85fe12eSEd Maste 	 * Issue a warning if there are VMA/LMA adjust requests for
331a85fe12eSEd Maste 	 * some nonexistent sections.
332a85fe12eSEd Maste 	 */
333a85fe12eSEd Maste 	if ((ecp->flags & NO_CHANGE_WARN) == 0) {
334a85fe12eSEd Maste 		STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
335a85fe12eSEd Maste 			if (!sac->setvma && !sac->setlma &&
336a85fe12eSEd Maste 			    !sac->vma_adjust && !sac->lma_adjust)
337a85fe12eSEd Maste 				continue;
338a85fe12eSEd Maste 			found = 0;
339a85fe12eSEd Maste 			TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
340a85fe12eSEd Maste 				if (s->pseudo || s->name == NULL)
341a85fe12eSEd Maste 					continue;
342a85fe12eSEd Maste 				if (!strcmp(s->name, sac->name)) {
343a85fe12eSEd Maste 					found = 1;
344a85fe12eSEd Maste 					break;
345a85fe12eSEd Maste 				}
346a85fe12eSEd Maste 			}
347a85fe12eSEd Maste 			if (!found)
348a85fe12eSEd Maste 				warnx("cannot find section `%s'", sac->name);
349a85fe12eSEd Maste 		}
350a85fe12eSEd Maste 	}
351a85fe12eSEd Maste }
352a85fe12eSEd Maste 
353a85fe12eSEd Maste static void
354a85fe12eSEd Maste insert_to_inseg_list(struct segment *seg, struct section *sec)
355a85fe12eSEd Maste {
356a85fe12eSEd Maste 	struct section *s;
357a85fe12eSEd Maste 	int i;
358a85fe12eSEd Maste 
359a85fe12eSEd Maste 	seg->nsec++;
360a85fe12eSEd Maste 	seg->v_sec = realloc(seg->v_sec, seg->nsec * sizeof(*seg->v_sec));
361a85fe12eSEd Maste 	if (seg->v_sec == NULL)
362a85fe12eSEd Maste 		err(EXIT_FAILURE, "realloc failed");
363a85fe12eSEd Maste 
364a85fe12eSEd Maste 	/*
365a85fe12eSEd Maste 	 * Sort the section in order of offset.
366a85fe12eSEd Maste 	 */
367a85fe12eSEd Maste 
368a85fe12eSEd Maste 	for (i = seg->nsec - 1; i > 0; i--) {
369a85fe12eSEd Maste 		s = seg->v_sec[i - 1];
370a85fe12eSEd Maste 		if (sec->off >= s->off) {
371a85fe12eSEd Maste 			seg->v_sec[i] = sec;
372a85fe12eSEd Maste 			break;
373a85fe12eSEd Maste 		} else
374a85fe12eSEd Maste 			seg->v_sec[i] = s;
375a85fe12eSEd Maste 	}
376a85fe12eSEd Maste 	if (i == 0)
377a85fe12eSEd Maste 		seg->v_sec[0] = sec;
378a85fe12eSEd Maste }
379a85fe12eSEd Maste 
380a85fe12eSEd Maste void
381a85fe12eSEd Maste setup_phdr(struct elfcopy *ecp)
382a85fe12eSEd Maste {
383a85fe12eSEd Maste 	struct segment	*seg;
384a85fe12eSEd Maste 	GElf_Phdr	 iphdr;
385a85fe12eSEd Maste 	size_t		 iphnum;
386a85fe12eSEd Maste 	int		 i;
387a85fe12eSEd Maste 
388a85fe12eSEd Maste 	if (elf_getphnum(ecp->ein, &iphnum) == 0)
389a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getphnum failed: %s",
390a85fe12eSEd Maste 		    elf_errmsg(-1));
391a85fe12eSEd Maste 
392a85fe12eSEd Maste 	ecp->ophnum = ecp->iphnum = iphnum;
393a85fe12eSEd Maste 	if (iphnum == 0)
394a85fe12eSEd Maste 		return;
395a85fe12eSEd Maste 
396a85fe12eSEd Maste 	/* If --only-keep-debug is specified, discard all program headers. */
397a85fe12eSEd Maste 	if (ecp->strip == STRIP_NONDEBUG) {
398a85fe12eSEd Maste 		ecp->ophnum = 0;
399a85fe12eSEd Maste 		return;
400a85fe12eSEd Maste 	}
401a85fe12eSEd Maste 
402a85fe12eSEd Maste 	for (i = 0; (size_t)i < iphnum; i++) {
403a85fe12eSEd Maste 		if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
404a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
405a85fe12eSEd Maste 			    elf_errmsg(-1));
406a85fe12eSEd Maste 		if ((seg = calloc(1, sizeof(*seg))) == NULL)
407a85fe12eSEd Maste 			err(EXIT_FAILURE, "calloc failed");
408a85fe12eSEd Maste 		seg->addr	= iphdr.p_vaddr;
409a85fe12eSEd Maste 		seg->off	= iphdr.p_offset;
410a85fe12eSEd Maste 		seg->fsz	= iphdr.p_filesz;
411a85fe12eSEd Maste 		seg->msz	= iphdr.p_memsz;
412a85fe12eSEd Maste 		seg->type	= iphdr.p_type;
413a85fe12eSEd Maste 		STAILQ_INSERT_TAIL(&ecp->v_seg, seg, seg_list);
414a85fe12eSEd Maste 	}
415a85fe12eSEd Maste }
416a85fe12eSEd Maste 
417a85fe12eSEd Maste void
418a85fe12eSEd Maste copy_phdr(struct elfcopy *ecp)
419a85fe12eSEd Maste {
420a85fe12eSEd Maste 	struct segment	*seg;
421a85fe12eSEd Maste 	struct section	*s;
422a85fe12eSEd Maste 	GElf_Phdr	 iphdr, ophdr;
423a85fe12eSEd Maste 	int		 i;
424a85fe12eSEd Maste 
425a85fe12eSEd Maste 	STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
426a85fe12eSEd Maste 		if (seg->type == PT_PHDR) {
427a85fe12eSEd Maste 			if (!TAILQ_EMPTY(&ecp->v_sec)) {
428a85fe12eSEd Maste 				s = TAILQ_FIRST(&ecp->v_sec);
429a85fe12eSEd Maste 				if (s->pseudo)
430a85fe12eSEd Maste 					seg->addr = s->lma +
431a85fe12eSEd Maste 					    gelf_fsize(ecp->eout, ELF_T_EHDR,
432a85fe12eSEd Maste 						1, EV_CURRENT);
433a85fe12eSEd Maste 			}
434a85fe12eSEd Maste 			seg->fsz = seg->msz = gelf_fsize(ecp->eout, ELF_T_PHDR,
435a85fe12eSEd Maste 			    ecp->ophnum, EV_CURRENT);
436a85fe12eSEd Maste 			continue;
437a85fe12eSEd Maste 		}
438a85fe12eSEd Maste 
439a85fe12eSEd Maste 		seg->fsz = seg->msz = 0;
440a85fe12eSEd Maste 		for (i = 0; i < seg->nsec; i++) {
441a85fe12eSEd Maste 			s = seg->v_sec[i];
442a85fe12eSEd Maste 			seg->msz = s->off + s->sz - seg->off;
443a85fe12eSEd Maste 			if (s->type != SHT_NOBITS)
444a85fe12eSEd Maste 				seg->fsz = seg->msz;
445a85fe12eSEd Maste 		}
446a85fe12eSEd Maste 	}
447a85fe12eSEd Maste 
448a85fe12eSEd Maste 	/*
449a85fe12eSEd Maste 	 * Allocate space for program headers, note that libelf keep
450a85fe12eSEd Maste 	 * track of the number in internal variable, and a call to
451a85fe12eSEd Maste 	 * elf_update is needed to update e_phnum of ehdr.
452a85fe12eSEd Maste 	 */
453a85fe12eSEd Maste 	if (gelf_newphdr(ecp->eout, ecp->ophnum) == NULL)
454a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_newphdr() failed: %s",
455a85fe12eSEd Maste 		    elf_errmsg(-1));
456a85fe12eSEd Maste 
457a85fe12eSEd Maste 	/*
458a85fe12eSEd Maste 	 * This elf_update() call is to update the e_phnum field in
459a85fe12eSEd Maste 	 * ehdr. It's necessary because later we will call gelf_getphdr(),
460a85fe12eSEd Maste 	 * which does sanity check by comparing ndx argument with e_phnum.
461a85fe12eSEd Maste 	 */
462a85fe12eSEd Maste 	if (elf_update(ecp->eout, ELF_C_NULL) < 0)
463a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1));
464a85fe12eSEd Maste 
465a85fe12eSEd Maste 	/*
466a85fe12eSEd Maste 	 * iphnum == ophnum, since we don't remove program headers even if
467a85fe12eSEd Maste 	 * they no longer contain sections.
468a85fe12eSEd Maste 	 */
469a85fe12eSEd Maste 	i = 0;
470a85fe12eSEd Maste 	STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
471a85fe12eSEd Maste 		if (i >= ecp->iphnum)
472a85fe12eSEd Maste 			break;
473a85fe12eSEd Maste 		if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
474a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
475a85fe12eSEd Maste 			    elf_errmsg(-1));
476a85fe12eSEd Maste 		if (gelf_getphdr(ecp->eout, i, &ophdr) != &ophdr)
477a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
478a85fe12eSEd Maste 			    elf_errmsg(-1));
479a85fe12eSEd Maste 
480a85fe12eSEd Maste 		ophdr.p_type = iphdr.p_type;
481a85fe12eSEd Maste 		ophdr.p_vaddr = seg->addr;
482a85fe12eSEd Maste 		ophdr.p_paddr = seg->addr;
483a85fe12eSEd Maste 		ophdr.p_flags = iphdr.p_flags;
484a85fe12eSEd Maste 		ophdr.p_align = iphdr.p_align;
485a85fe12eSEd Maste 		ophdr.p_offset = seg->off;
486a85fe12eSEd Maste 		ophdr.p_filesz = seg->fsz;
487a85fe12eSEd Maste 		ophdr.p_memsz = seg->msz;
488a85fe12eSEd Maste 		if (!gelf_update_phdr(ecp->eout, i, &ophdr))
489a85fe12eSEd Maste 			err(EXIT_FAILURE, "gelf_update_phdr failed :%s",
490a85fe12eSEd Maste 			    elf_errmsg(-1));
491a85fe12eSEd Maste 
492a85fe12eSEd Maste 		i++;
493a85fe12eSEd Maste 	}
494a85fe12eSEd Maste }
495