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