1260684Skaiw/*-
2260684Skaiw * Copyright (c) 2007-2010,2012 Kai Wang
3260684Skaiw * All rights reserved.
4260684Skaiw *
5260684Skaiw * Redistribution and use in source and binary forms, with or without
6260684Skaiw * modification, are permitted provided that the following conditions
7260684Skaiw * are met:
8260684Skaiw * 1. Redistributions of source code must retain the above copyright
9260684Skaiw *    notice, this list of conditions and the following disclaimer.
10260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright
11260684Skaiw *    notice, this list of conditions and the following disclaimer in the
12260684Skaiw *    documentation and/or other materials provided with the distribution.
13260684Skaiw *
14260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15260684Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16260684Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17260684Skaiw * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18260684Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19260684Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20260684Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21260684Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22260684Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23260684Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24260684Skaiw * SUCH DAMAGE.
25260684Skaiw */
26260684Skaiw
27260684Skaiw#include <sys/queue.h>
28260684Skaiw#include <err.h>
29260684Skaiw#include <gelf.h>
30275369Semaste#include <stdint.h>
31260684Skaiw#include <stdio.h>
32260684Skaiw#include <stdlib.h>
33260684Skaiw#include <string.h>
34260684Skaiw
35260684Skaiw#include "elfcopy.h"
36260684Skaiw
37367466SdimELFTC_VCSID("$Id: segments.c 3615 2018-05-17 04:12:24Z kaiwang27 $");
38260684Skaiw
39260684Skaiwstatic void	insert_to_inseg_list(struct segment *seg, struct section *sec);
40260684Skaiw
41260684Skaiw/*
42260684Skaiw * elfcopy's segment handling is relatively simpler and less powerful than
43260684Skaiw * libbfd. Program headers are modified or copied from input to output objects,
44260684Skaiw * but never re-generated. As a result, if the input object has incorrect
45260684Skaiw * program headers, the output object's program headers will remain incorrect
46260684Skaiw * or become even worse.
47260684Skaiw */
48260684Skaiw
49260684Skaiw/*
50260684Skaiw * Check whether a section is "loadable". If so, add it to the
51260684Skaiw * corresponding segment list(s) and return 1.
52260684Skaiw */
53260684Skaiwint
54260684Skaiwadd_to_inseg_list(struct elfcopy *ecp, struct section *s)
55260684Skaiw{
56260684Skaiw	struct segment	*seg;
57260684Skaiw	int		 loadable;
58260684Skaiw
59260684Skaiw	if (ecp->ophnum == 0)
60260684Skaiw		return (0);
61260684Skaiw
62260684Skaiw	/*
63260684Skaiw	 * Segment is a different view of an ELF object. One segment can
64260684Skaiw	 * contain one or more sections, and one section can be included
65260684Skaiw	 * in one or more segments, or not included in any segment at all.
66260684Skaiw	 * We call those sections which can be found in one or more segments
67260684Skaiw	 * "loadable" sections, and call the rest "unloadable" sections.
68260684Skaiw	 * We keep track of "loadable" sections in their containing
69260684Skaiw	 * segment(s)' v_sec queue. These information are later used to
70260684Skaiw	 * recalculate the extents of segments, when sections are removed,
71260684Skaiw	 * for example.
72260684Skaiw	 */
73260684Skaiw	loadable = 0;
74260684Skaiw	STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
75297242Semaste		if (s->off < seg->off || (s->vma < seg->vaddr && !s->pseudo))
76260684Skaiw			continue;
77260684Skaiw		if (s->off + s->sz > seg->off + seg->fsz &&
78260684Skaiw		    s->type != SHT_NOBITS)
79260684Skaiw			continue;
80297242Semaste		if (s->vma + s->sz > seg->vaddr + seg->msz)
81276371Semaste			continue;
82333770Smarius		if (seg->type == PT_TLS && ((s->flags & SHF_TLS) == 0))
83333770Smarius			continue;
84260684Skaiw
85260684Skaiw		insert_to_inseg_list(seg, s);
86260684Skaiw		if (seg->type == PT_LOAD)
87260684Skaiw			s->seg = seg;
88276398Semaste		else if (seg->type == PT_TLS)
89276398Semaste			s->seg_tls = seg;
90297242Semaste		if (s->pseudo)
91297242Semaste			s->vma = seg->vaddr + (s->off - seg->off);
92297242Semaste		if (seg->paddr > 0)
93297242Semaste			s->lma = seg->paddr + (s->off - seg->off);
94297242Semaste		else
95297242Semaste			s->lma = 0;
96260684Skaiw		loadable = 1;
97260684Skaiw	}
98260684Skaiw
99260684Skaiw	return (loadable);
100260684Skaiw}
101260684Skaiw
102260684Skaiwvoid
103260684Skaiwadjust_addr(struct elfcopy *ecp)
104260684Skaiw{
105260684Skaiw	struct section *s, *s0;
106260684Skaiw	struct segment *seg;
107260684Skaiw	struct sec_action *sac;
108297242Semaste	uint64_t dl, vma, lma, start, end;
109260684Skaiw	int found, i;
110260684Skaiw
111260684Skaiw	/*
112260684Skaiw	 * Apply VMA and global LMA changes in the first iteration.
113260684Skaiw	 */
114260684Skaiw	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
115260684Skaiw
116260684Skaiw		/* Only adjust loadable section's address. */
117295577Semaste		if (!s->loadable)
118260684Skaiw			continue;
119260684Skaiw
120297242Semaste		/* Apply global VMA adjustment. */
121297242Semaste		if (ecp->change_addr != 0)
122297242Semaste			s->vma += ecp->change_addr;
123297242Semaste
124260684Skaiw		/* Apply global LMA adjustment. */
125297242Semaste		if (ecp->change_addr != 0 && s->seg != NULL &&
126297242Semaste		    s->seg->paddr > 0)
127260684Skaiw			s->lma += ecp->change_addr;
128260684Skaiw	}
129260684Skaiw
130260684Skaiw	/*
131297242Semaste	 * Apply sections VMA change in the second iteration.
132260684Skaiw	 */
133260684Skaiw	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
134260684Skaiw
135297242Semaste		if (!s->loadable)
136260684Skaiw			continue;
137260684Skaiw
138260684Skaiw		/*
139297242Semaste		 * Check if there is a VMA change request for this
140260684Skaiw		 * section.
141260684Skaiw		 */
142260684Skaiw		sac = lookup_sec_act(ecp, s->name, 0);
143260684Skaiw		if (sac == NULL)
144260684Skaiw			continue;
145297242Semaste		vma = s->vma;
146297242Semaste		if (sac->setvma)
147297242Semaste			vma = sac->vma;
148297242Semaste		if (sac->vma_adjust != 0)
149297242Semaste			vma += sac->vma_adjust;
150297242Semaste		if (vma == s->vma)
151260684Skaiw			continue;
152297242Semaste
153297242Semaste		/*
154297242Semaste		 * No need to make segment adjustment if the section doesn't
155297242Semaste		 * belong to any segment.
156297242Semaste		 */
157297242Semaste		if (s->seg == NULL) {
158297242Semaste			s->vma = vma;
159260684Skaiw			continue;
160297242Semaste		}
161260684Skaiw
162260684Skaiw		/*
163297242Semaste		 * Check if the VMA change is viable.
164260684Skaiw		 *
165297242Semaste		 * 1. Check if the new VMA is properly aligned accroding to
166260684Skaiw		 *    section alignment.
167260684Skaiw		 *
168260684Skaiw		 * 2. Compute the new extent of segment that contains this
169260684Skaiw		 *    section, make sure it doesn't overlap with other
170260684Skaiw		 *    segments.
171260684Skaiw		 */
172260684Skaiw#ifdef	DEBUG
173297242Semaste		printf("VMA for section %s: %#jx\n", s->name, vma);
174260684Skaiw#endif
175260684Skaiw
176297242Semaste		if (vma % s->align != 0)
177297242Semaste			errx(EXIT_FAILURE, "The VMA %#jx for "
178260684Skaiw			    "section %s is not aligned to %ju",
179297242Semaste			    (uintmax_t) vma, s->name, (uintmax_t) s->align);
180260684Skaiw
181297242Semaste		if (vma < s->vma) {
182260684Skaiw			/* Move section to lower address. */
183297242Semaste			if (vma < s->vma - s->seg->vaddr)
184260684Skaiw				errx(EXIT_FAILURE, "Not enough space to move "
185297242Semaste				    "section %s VMA to %#jx", s->name,
186297242Semaste				    (uintmax_t) vma);
187297242Semaste			start = vma - (s->vma - s->seg->vaddr);
188260684Skaiw			if (s == s->seg->v_sec[s->seg->nsec - 1])
189260684Skaiw				end = start + s->seg->msz;
190260684Skaiw			else
191297242Semaste				end = s->seg->vaddr + s->seg->msz;
192260684Skaiw		} else {
193260684Skaiw			/* Move section to upper address. */
194260684Skaiw			if (s == s->seg->v_sec[0])
195297242Semaste				start = vma;
196260684Skaiw			else
197297242Semaste				start = s->seg->vaddr;
198297242Semaste			end = vma + (s->seg->vaddr + s->seg->msz - s->vma);
199260684Skaiw			if (end < start)
200260684Skaiw				errx(EXIT_FAILURE, "Not enough space to move "
201297242Semaste				    "section %s VMA to %#jx", s->name,
202297242Semaste				    (uintmax_t) vma);
203260684Skaiw		}
204260684Skaiw
205260684Skaiw#ifdef	DEBUG
206260684Skaiw		printf("new extent for segment containing %s: (%#jx,%#jx)\n",
207260684Skaiw		    s->name, start, end);
208260684Skaiw#endif
209260684Skaiw
210260684Skaiw		STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
211260684Skaiw			if (seg == s->seg || seg->type != PT_LOAD)
212260684Skaiw				continue;
213297242Semaste			if (start > seg->vaddr + seg->msz)
214260684Skaiw				continue;
215297242Semaste			if (end < seg->vaddr)
216260684Skaiw				continue;
217260684Skaiw			errx(EXIT_FAILURE, "The extent of segment containing "
218260684Skaiw			    "section %s overlaps with segment(%#jx,%#jx)",
219297242Semaste			    s->name, (uintmax_t) seg->vaddr,
220297242Semaste			    (uintmax_t) (seg->vaddr + seg->msz));
221260684Skaiw		}
222260684Skaiw
223260684Skaiw		/*
224297242Semaste		 * Update section VMA and file offset.
225260684Skaiw		 */
226260684Skaiw
227297242Semaste		if (vma < s->vma) {
228260684Skaiw			/*
229297242Semaste			 * To move a section to lower VMA, we decrease
230297242Semaste			 * the VMA of the section and all the sections that
231297242Semaste			 * are before it, and we increase the file offsets
232297242Semaste			 * of all the sections that are after it.
233260684Skaiw			 */
234297242Semaste			dl = s->vma - vma;
235260684Skaiw			for (i = 0; i < s->seg->nsec; i++) {
236260684Skaiw				s0 = s->seg->v_sec[i];
237297242Semaste				s0->vma -= dl;
238260684Skaiw#ifdef	DEBUG
239297242Semaste				printf("section %s VMA set to %#jx\n",
240297242Semaste				    s0->name, (uintmax_t) s0->vma);
241260684Skaiw#endif
242260684Skaiw				if (s0 == s)
243260684Skaiw					break;
244260684Skaiw			}
245260684Skaiw			for (i = i + 1; i < s->seg->nsec; i++) {
246260684Skaiw				s0 = s->seg->v_sec[i];
247260684Skaiw				s0->off += dl;
248260684Skaiw#ifdef	DEBUG
249260684Skaiw				printf("section %s offset set to %#jx\n",
250260684Skaiw				    s0->name, (uintmax_t) s0->off);
251260684Skaiw#endif
252260684Skaiw			}
253260684Skaiw		} else {
254260684Skaiw			/*
255297242Semaste			 * To move a section to upper VMA, we increase
256297242Semaste			 * the VMA of the section and all the sections that
257297242Semaste			 * are after it, and we increase the their file
258297242Semaste			 * offsets too unless the section in question
259260684Skaiw			 * is the first in its containing segment.
260260684Skaiw			 */
261297242Semaste			dl = vma - s->vma;
262260684Skaiw			for (i = 0; i < s->seg->nsec; i++)
263260684Skaiw				if (s->seg->v_sec[i] == s)
264260684Skaiw					break;
265260684Skaiw			if (i >= s->seg->nsec)
266260684Skaiw				errx(EXIT_FAILURE, "Internal: section `%s' not"
267260684Skaiw				    " found in its containing segement",
268260684Skaiw				    s->name);
269260684Skaiw			for (; i < s->seg->nsec; i++) {
270260684Skaiw				s0 = s->seg->v_sec[i];
271297242Semaste				s0->vma += dl;
272260684Skaiw#ifdef	DEBUG
273297242Semaste				printf("section %s VMA set to %#jx\n",
274260684Skaiw				    s0->name, (uintmax_t) s0->lma);
275260684Skaiw#endif
276260684Skaiw				if (s != s->seg->v_sec[0]) {
277260684Skaiw					s0->off += dl;
278260684Skaiw#ifdef	DEBUG
279260684Skaiw					printf("section %s offset set to %#jx\n",
280260684Skaiw					    s0->name, (uintmax_t) s0->off);
281260684Skaiw#endif
282260684Skaiw				}
283260684Skaiw			}
284260684Skaiw		}
285260684Skaiw	}
286260684Skaiw
287260684Skaiw	/*
288260684Skaiw	 * Apply load address padding.
289260684Skaiw	 */
290260684Skaiw
291260684Skaiw	if (ecp->pad_to != 0) {
292260684Skaiw
293260684Skaiw		/*
294297242Semaste		 * Find the section with highest VMA.
295260684Skaiw		 */
296260684Skaiw		s = NULL;
297260684Skaiw		STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
298260684Skaiw			if (seg->type != PT_LOAD)
299260684Skaiw				continue;
300260684Skaiw			for (i = seg->nsec - 1; i >= 0; i--)
301260684Skaiw				if (seg->v_sec[i]->type != SHT_NOBITS)
302260684Skaiw					break;
303260684Skaiw			if (i < 0)
304260684Skaiw				continue;
305260684Skaiw			if (s == NULL)
306260684Skaiw				s = seg->v_sec[i];
307260684Skaiw			else {
308260684Skaiw				s0 = seg->v_sec[i];
309297242Semaste				if (s0->vma > s->vma)
310260684Skaiw					s = s0;
311260684Skaiw			}
312260684Skaiw		}
313260684Skaiw
314260684Skaiw		if (s == NULL)
315297242Semaste			goto adjust_lma;
316260684Skaiw
317260684Skaiw		/* No need to pad if the pad_to address is lower. */
318297242Semaste		if (ecp->pad_to <= s->vma + s->sz)
319297242Semaste			goto adjust_lma;
320260684Skaiw
321297242Semaste		s->pad_sz = ecp->pad_to - (s->vma + s->sz);
322260684Skaiw#ifdef	DEBUG
323297242Semaste		printf("pad section %s VMA to address %#jx by %#jx\n", s->name,
324260684Skaiw		    (uintmax_t) ecp->pad_to, (uintmax_t) s->pad_sz);
325260684Skaiw#endif
326260684Skaiw	}
327260684Skaiw
328260684Skaiw
329297242Semasteadjust_lma:
330297242Semaste
331260684Skaiw	/*
332297242Semaste	 * Apply sections LMA change in the third iteration.
333297242Semaste	 */
334297242Semaste	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
335297242Semaste
336297242Semaste		/*
337297242Semaste		 * Only loadable section that's inside a segment can have
338297242Semaste		 * LMA adjusted. Also, if LMA of the containing segment is
339297242Semaste		 * set to 0, it probably means we should ignore the LMA.
340297242Semaste		 */
341297242Semaste		if (!s->loadable || s->seg == NULL || s->seg->paddr == 0)
342297242Semaste			continue;
343297242Semaste
344297242Semaste		/*
345297242Semaste		 * Check if there is a LMA change request for this
346297242Semaste		 * section.
347297242Semaste		 */
348297242Semaste		sac = lookup_sec_act(ecp, s->name, 0);
349297242Semaste		if (sac == NULL)
350297242Semaste			continue;
351297242Semaste		if (!sac->setlma && sac->lma_adjust == 0)
352297242Semaste			continue;
353297242Semaste		lma = s->lma;
354297242Semaste		if (sac->setlma)
355297242Semaste			lma = sac->lma;
356297242Semaste		if (sac->lma_adjust != 0)
357297242Semaste			lma += sac->lma_adjust;
358297242Semaste		if (lma == s->lma)
359297242Semaste			continue;
360297242Semaste
361297242Semaste#ifdef	DEBUG
362297242Semaste		printf("LMA for section %s: %#jx\n", s->name, lma);
363297242Semaste#endif
364297242Semaste
365297242Semaste		/* Check alignment. */
366297242Semaste		if (lma % s->align != 0)
367297242Semaste			errx(EXIT_FAILURE, "The LMA %#jx for "
368297242Semaste			    "section %s is not aligned to %ju",
369297242Semaste			    (uintmax_t) lma, s->name, (uintmax_t) s->align);
370297242Semaste
371297242Semaste		/*
372297242Semaste		 * Update section LMA.
373297242Semaste		 */
374297242Semaste
375297242Semaste		if (lma < s->lma) {
376297242Semaste			/*
377297242Semaste			 * To move a section to lower LMA, we decrease
378297242Semaste			 * the LMA of the section and all the sections that
379297242Semaste			 * are before it.
380297242Semaste			 */
381297242Semaste			dl = s->lma - lma;
382297242Semaste			for (i = 0; i < s->seg->nsec; i++) {
383297242Semaste				s0 = s->seg->v_sec[i];
384297242Semaste				s0->lma -= dl;
385297242Semaste#ifdef	DEBUG
386297242Semaste				printf("section %s LMA set to %#jx\n",
387297242Semaste				    s0->name, (uintmax_t) s0->lma);
388297242Semaste#endif
389297242Semaste				if (s0 == s)
390297242Semaste					break;
391297242Semaste			}
392297242Semaste		} else {
393297242Semaste			/*
394297242Semaste			 * To move a section to upper LMA, we increase
395297242Semaste			 * the LMA of the section and all the sections that
396297242Semaste			 * are after it.
397297242Semaste			 */
398297242Semaste			dl = lma - s->lma;
399297242Semaste			for (i = 0; i < s->seg->nsec; i++)
400297242Semaste				if (s->seg->v_sec[i] == s)
401297242Semaste					break;
402297242Semaste			if (i >= s->seg->nsec)
403297242Semaste				errx(EXIT_FAILURE, "Internal: section `%s' not"
404297242Semaste				    " found in its containing segement",
405297242Semaste				    s->name);
406297242Semaste			for (; i < s->seg->nsec; i++) {
407297242Semaste				s0 = s->seg->v_sec[i];
408297242Semaste				s0->lma += dl;
409297242Semaste#ifdef	DEBUG
410297242Semaste				printf("section %s LMA set to %#jx\n",
411297242Semaste				    s0->name, (uintmax_t) s0->lma);
412297242Semaste#endif
413297242Semaste			}
414297242Semaste		}
415297242Semaste	}
416297242Semaste
417297242Semaste	/*
418260684Skaiw	 * Issue a warning if there are VMA/LMA adjust requests for
419260684Skaiw	 * some nonexistent sections.
420260684Skaiw	 */
421260684Skaiw	if ((ecp->flags & NO_CHANGE_WARN) == 0) {
422260684Skaiw		STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
423260684Skaiw			if (!sac->setvma && !sac->setlma &&
424260684Skaiw			    !sac->vma_adjust && !sac->lma_adjust)
425260684Skaiw				continue;
426260684Skaiw			found = 0;
427260684Skaiw			TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
428260684Skaiw				if (s->pseudo || s->name == NULL)
429260684Skaiw					continue;
430260684Skaiw				if (!strcmp(s->name, sac->name)) {
431260684Skaiw					found = 1;
432260684Skaiw					break;
433260684Skaiw				}
434260684Skaiw			}
435260684Skaiw			if (!found)
436260684Skaiw				warnx("cannot find section `%s'", sac->name);
437260684Skaiw		}
438260684Skaiw	}
439260684Skaiw}
440260684Skaiw
441260684Skaiwstatic void
442260684Skaiwinsert_to_inseg_list(struct segment *seg, struct section *sec)
443260684Skaiw{
444260684Skaiw	struct section *s;
445260684Skaiw	int i;
446260684Skaiw
447260684Skaiw	seg->nsec++;
448260684Skaiw	seg->v_sec = realloc(seg->v_sec, seg->nsec * sizeof(*seg->v_sec));
449260684Skaiw	if (seg->v_sec == NULL)
450260684Skaiw		err(EXIT_FAILURE, "realloc failed");
451260684Skaiw
452260684Skaiw	/*
453260684Skaiw	 * Sort the section in order of offset.
454260684Skaiw	 */
455260684Skaiw
456260684Skaiw	for (i = seg->nsec - 1; i > 0; i--) {
457260684Skaiw		s = seg->v_sec[i - 1];
458260684Skaiw		if (sec->off >= s->off) {
459260684Skaiw			seg->v_sec[i] = sec;
460260684Skaiw			break;
461260684Skaiw		} else
462260684Skaiw			seg->v_sec[i] = s;
463260684Skaiw	}
464260684Skaiw	if (i == 0)
465260684Skaiw		seg->v_sec[0] = sec;
466260684Skaiw}
467260684Skaiw
468260684Skaiwvoid
469260684Skaiwsetup_phdr(struct elfcopy *ecp)
470260684Skaiw{
471260684Skaiw	struct segment	*seg;
472260684Skaiw	GElf_Phdr	 iphdr;
473300311Semaste	size_t		 iphnum, i;
474260684Skaiw
475260684Skaiw	if (elf_getphnum(ecp->ein, &iphnum) == 0)
476260684Skaiw		errx(EXIT_FAILURE, "elf_getphnum failed: %s",
477260684Skaiw		    elf_errmsg(-1));
478260684Skaiw
479260684Skaiw	ecp->ophnum = ecp->iphnum = iphnum;
480260684Skaiw	if (iphnum == 0)
481260684Skaiw		return;
482260684Skaiw
483260684Skaiw	/* If --only-keep-debug is specified, discard all program headers. */
484260684Skaiw	if (ecp->strip == STRIP_NONDEBUG) {
485260684Skaiw		ecp->ophnum = 0;
486260684Skaiw		return;
487260684Skaiw	}
488260684Skaiw
489300311Semaste	for (i = 0; i < iphnum; i++) {
490260684Skaiw		if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
491260684Skaiw			errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
492260684Skaiw			    elf_errmsg(-1));
493260684Skaiw		if ((seg = calloc(1, sizeof(*seg))) == NULL)
494260684Skaiw			err(EXIT_FAILURE, "calloc failed");
495297242Semaste		seg->vaddr	= iphdr.p_vaddr;
496297242Semaste		seg->paddr	= iphdr.p_paddr;
497260684Skaiw		seg->off	= iphdr.p_offset;
498260684Skaiw		seg->fsz	= iphdr.p_filesz;
499260684Skaiw		seg->msz	= iphdr.p_memsz;
500260684Skaiw		seg->type	= iphdr.p_type;
501260684Skaiw		STAILQ_INSERT_TAIL(&ecp->v_seg, seg, seg_list);
502260684Skaiw	}
503260684Skaiw}
504260684Skaiw
505260684Skaiwvoid
506260684Skaiwcopy_phdr(struct elfcopy *ecp)
507260684Skaiw{
508260684Skaiw	struct segment	*seg;
509260684Skaiw	struct section	*s;
510260684Skaiw	GElf_Phdr	 iphdr, ophdr;
511260684Skaiw	int		 i;
512260684Skaiw
513260684Skaiw	STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
514260684Skaiw		if (seg->type == PT_PHDR) {
515260684Skaiw			if (!TAILQ_EMPTY(&ecp->v_sec)) {
516260684Skaiw				s = TAILQ_FIRST(&ecp->v_sec);
517297242Semaste				if (s->pseudo) {
518297242Semaste					seg->vaddr = s->vma +
519260684Skaiw					    gelf_fsize(ecp->eout, ELF_T_EHDR,
520260684Skaiw						1, EV_CURRENT);
521297242Semaste					seg->paddr = s->lma +
522297242Semaste					    gelf_fsize(ecp->eout, ELF_T_EHDR,
523297242Semaste						1, EV_CURRENT);
524297242Semaste				}
525260684Skaiw			}
526260684Skaiw			seg->fsz = seg->msz = gelf_fsize(ecp->eout, ELF_T_PHDR,
527260684Skaiw			    ecp->ophnum, EV_CURRENT);
528260684Skaiw			continue;
529260684Skaiw		}
530260684Skaiw
531297242Semaste		if (seg->nsec > 0) {
532297242Semaste			s = seg->v_sec[0];
533297242Semaste			seg->vaddr = s->vma;
534297242Semaste			seg->paddr = s->lma;
535297242Semaste		}
536297242Semaste
537260684Skaiw		seg->fsz = seg->msz = 0;
538260684Skaiw		for (i = 0; i < seg->nsec; i++) {
539260684Skaiw			s = seg->v_sec[i];
540297242Semaste			seg->msz = s->vma + s->sz - seg->vaddr;
541260684Skaiw			if (s->type != SHT_NOBITS)
542282918Semaste				seg->fsz = s->off + s->sz - seg->off;
543260684Skaiw		}
544260684Skaiw	}
545260684Skaiw
546260684Skaiw	/*
547260684Skaiw	 * Allocate space for program headers, note that libelf keep
548260684Skaiw	 * track of the number in internal variable, and a call to
549260684Skaiw	 * elf_update is needed to update e_phnum of ehdr.
550260684Skaiw	 */
551260684Skaiw	if (gelf_newphdr(ecp->eout, ecp->ophnum) == NULL)
552260684Skaiw		errx(EXIT_FAILURE, "gelf_newphdr() failed: %s",
553260684Skaiw		    elf_errmsg(-1));
554260684Skaiw
555260684Skaiw	/*
556260684Skaiw	 * This elf_update() call is to update the e_phnum field in
557260684Skaiw	 * ehdr. It's necessary because later we will call gelf_getphdr(),
558260684Skaiw	 * which does sanity check by comparing ndx argument with e_phnum.
559260684Skaiw	 */
560260684Skaiw	if (elf_update(ecp->eout, ELF_C_NULL) < 0)
561260684Skaiw		errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1));
562260684Skaiw
563260684Skaiw	/*
564260684Skaiw	 * iphnum == ophnum, since we don't remove program headers even if
565260684Skaiw	 * they no longer contain sections.
566260684Skaiw	 */
567260684Skaiw	i = 0;
568260684Skaiw	STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
569260684Skaiw		if (i >= ecp->iphnum)
570260684Skaiw			break;
571260684Skaiw		if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
572260684Skaiw			errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
573260684Skaiw			    elf_errmsg(-1));
574260684Skaiw		if (gelf_getphdr(ecp->eout, i, &ophdr) != &ophdr)
575260684Skaiw			errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
576260684Skaiw			    elf_errmsg(-1));
577260684Skaiw
578260684Skaiw		ophdr.p_type = iphdr.p_type;
579297242Semaste		ophdr.p_vaddr = seg->vaddr;
580297242Semaste		ophdr.p_paddr = seg->paddr;
581260684Skaiw		ophdr.p_flags = iphdr.p_flags;
582260684Skaiw		ophdr.p_align = iphdr.p_align;
583260684Skaiw		ophdr.p_offset = seg->off;
584260684Skaiw		ophdr.p_filesz = seg->fsz;
585260684Skaiw		ophdr.p_memsz = seg->msz;
586260684Skaiw		if (!gelf_update_phdr(ecp->eout, i, &ophdr))
587295577Semaste			errx(EXIT_FAILURE, "gelf_update_phdr failed: %s",
588260684Skaiw			    elf_errmsg(-1));
589260684Skaiw
590260684Skaiw		i++;
591260684Skaiw	}
592260684Skaiw}
593