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/queue.h>
28a85fe12eSEd Maste #include <err.h>
29a85fe12eSEd Maste #include <gelf.h>
3050f69bfbSEd Maste #include <stdint.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
37*ae500c1fSEd Maste ELFTC_VCSID("$Id: segments.c 3615 2018-05-17 04:12:24Z kaiwang27 $");
38a85fe12eSEd Maste
39a85fe12eSEd Maste static void insert_to_inseg_list(struct segment *seg, struct section *sec);
40a85fe12eSEd Maste
41a85fe12eSEd Maste /*
42a85fe12eSEd Maste * elfcopy's segment handling is relatively simpler and less powerful than
43a85fe12eSEd Maste * libbfd. Program headers are modified or copied from input to output objects,
44a85fe12eSEd Maste * but never re-generated. As a result, if the input object has incorrect
45a85fe12eSEd Maste * program headers, the output object's program headers will remain incorrect
46a85fe12eSEd Maste * or become even worse.
47a85fe12eSEd Maste */
48a85fe12eSEd Maste
49a85fe12eSEd Maste /*
50a85fe12eSEd Maste * Check whether a section is "loadable". If so, add it to the
51a85fe12eSEd Maste * corresponding segment list(s) and return 1.
52a85fe12eSEd Maste */
53a85fe12eSEd Maste int
add_to_inseg_list(struct elfcopy * ecp,struct section * s)54a85fe12eSEd Maste add_to_inseg_list(struct elfcopy *ecp, struct section *s)
55a85fe12eSEd Maste {
56a85fe12eSEd Maste struct segment *seg;
57a85fe12eSEd Maste int loadable;
58a85fe12eSEd Maste
59a85fe12eSEd Maste if (ecp->ophnum == 0)
60a85fe12eSEd Maste return (0);
61a85fe12eSEd Maste
62a85fe12eSEd Maste /*
63a85fe12eSEd Maste * Segment is a different view of an ELF object. One segment can
64a85fe12eSEd Maste * contain one or more sections, and one section can be included
65a85fe12eSEd Maste * in one or more segments, or not included in any segment at all.
66a85fe12eSEd Maste * We call those sections which can be found in one or more segments
67a85fe12eSEd Maste * "loadable" sections, and call the rest "unloadable" sections.
68a85fe12eSEd Maste * We keep track of "loadable" sections in their containing
69a85fe12eSEd Maste * segment(s)' v_sec queue. These information are later used to
70a85fe12eSEd Maste * recalculate the extents of segments, when sections are removed,
71a85fe12eSEd Maste * for example.
72a85fe12eSEd Maste */
73a85fe12eSEd Maste loadable = 0;
74a85fe12eSEd Maste STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
75676e25abSEd Maste if (s->off < seg->off || (s->vma < seg->vaddr && !s->pseudo))
76a85fe12eSEd Maste continue;
77a85fe12eSEd Maste if (s->off + s->sz > seg->off + seg->fsz &&
78a85fe12eSEd Maste s->type != SHT_NOBITS)
79a85fe12eSEd Maste continue;
80676e25abSEd Maste if (s->vma + s->sz > seg->vaddr + seg->msz)
81cf781b2eSEd Maste continue;
8248d41ef0SPhil Shafer if (seg->type == PT_TLS && ((s->flags & SHF_TLS) == 0))
8348d41ef0SPhil Shafer continue;
84a85fe12eSEd Maste
85a85fe12eSEd Maste insert_to_inseg_list(seg, s);
86a85fe12eSEd Maste if (seg->type == PT_LOAD)
87a85fe12eSEd Maste s->seg = seg;
884a85c691SEd Maste else if (seg->type == PT_TLS)
894a85c691SEd Maste s->seg_tls = seg;
90676e25abSEd Maste if (s->pseudo)
91676e25abSEd Maste s->vma = seg->vaddr + (s->off - seg->off);
92676e25abSEd Maste if (seg->paddr > 0)
93676e25abSEd Maste s->lma = seg->paddr + (s->off - seg->off);
94676e25abSEd Maste else
95676e25abSEd Maste s->lma = 0;
96a85fe12eSEd Maste loadable = 1;
97a85fe12eSEd Maste }
98a85fe12eSEd Maste
99a85fe12eSEd Maste return (loadable);
100a85fe12eSEd Maste }
101a85fe12eSEd Maste
102a85fe12eSEd Maste void
adjust_addr(struct elfcopy * ecp)103a85fe12eSEd Maste adjust_addr(struct elfcopy *ecp)
104a85fe12eSEd Maste {
105a85fe12eSEd Maste struct section *s, *s0;
106a85fe12eSEd Maste struct segment *seg;
107a85fe12eSEd Maste struct sec_action *sac;
108676e25abSEd Maste uint64_t dl, vma, lma, start, end;
109a85fe12eSEd Maste int found, i;
110a85fe12eSEd Maste
111a85fe12eSEd Maste /*
112a85fe12eSEd Maste * Apply VMA and global LMA changes in the first iteration.
113a85fe12eSEd Maste */
114a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
115a85fe12eSEd Maste
116a85fe12eSEd Maste /* Only adjust loadable section's address. */
117839529caSEd Maste if (!s->loadable)
118a85fe12eSEd Maste continue;
119a85fe12eSEd Maste
120a85fe12eSEd Maste /* Apply global VMA adjustment. */
121a85fe12eSEd Maste if (ecp->change_addr != 0)
122a85fe12eSEd Maste s->vma += ecp->change_addr;
123a85fe12eSEd Maste
124676e25abSEd Maste /* Apply global LMA adjustment. */
125676e25abSEd Maste if (ecp->change_addr != 0 && s->seg != NULL &&
126676e25abSEd Maste s->seg->paddr > 0)
127676e25abSEd Maste s->lma += ecp->change_addr;
128a85fe12eSEd Maste }
129a85fe12eSEd Maste
130a85fe12eSEd Maste /*
131676e25abSEd Maste * Apply sections VMA change in the second iteration.
132a85fe12eSEd Maste */
133a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
134a85fe12eSEd Maste
135676e25abSEd Maste if (!s->loadable)
136a85fe12eSEd Maste continue;
137a85fe12eSEd Maste
138a85fe12eSEd Maste /*
139676e25abSEd Maste * Check if there is a VMA change request for this
140a85fe12eSEd Maste * section.
141a85fe12eSEd Maste */
142a85fe12eSEd Maste sac = lookup_sec_act(ecp, s->name, 0);
143a85fe12eSEd Maste if (sac == NULL)
144a85fe12eSEd Maste continue;
145676e25abSEd Maste vma = s->vma;
146676e25abSEd Maste if (sac->setvma)
147676e25abSEd Maste vma = sac->vma;
148676e25abSEd Maste if (sac->vma_adjust != 0)
149676e25abSEd Maste vma += sac->vma_adjust;
150676e25abSEd Maste if (vma == s->vma)
151a85fe12eSEd Maste continue;
152a85fe12eSEd Maste
153a85fe12eSEd Maste /*
154676e25abSEd Maste * No need to make segment adjustment if the section doesn't
155676e25abSEd Maste * belong to any segment.
156676e25abSEd Maste */
157676e25abSEd Maste if (s->seg == NULL) {
158676e25abSEd Maste s->vma = vma;
159676e25abSEd Maste continue;
160676e25abSEd Maste }
161676e25abSEd Maste
162676e25abSEd Maste /*
163676e25abSEd Maste * Check if the VMA change is viable.
164a85fe12eSEd Maste *
165676e25abSEd Maste * 1. Check if the new VMA is properly aligned accroding to
166a85fe12eSEd Maste * section alignment.
167a85fe12eSEd Maste *
168a85fe12eSEd Maste * 2. Compute the new extent of segment that contains this
169a85fe12eSEd Maste * section, make sure it doesn't overlap with other
170a85fe12eSEd Maste * segments.
171a85fe12eSEd Maste */
172a85fe12eSEd Maste #ifdef DEBUG
173676e25abSEd Maste printf("VMA for section %s: %#jx\n", s->name, vma);
174a85fe12eSEd Maste #endif
175a85fe12eSEd Maste
176676e25abSEd Maste if (vma % s->align != 0)
177676e25abSEd Maste errx(EXIT_FAILURE, "The VMA %#jx for "
178a85fe12eSEd Maste "section %s is not aligned to %ju",
179676e25abSEd Maste (uintmax_t) vma, s->name, (uintmax_t) s->align);
180a85fe12eSEd Maste
181676e25abSEd Maste if (vma < s->vma) {
182a85fe12eSEd Maste /* Move section to lower address. */
183676e25abSEd Maste if (vma < s->vma - s->seg->vaddr)
184a85fe12eSEd Maste errx(EXIT_FAILURE, "Not enough space to move "
185676e25abSEd Maste "section %s VMA to %#jx", s->name,
186676e25abSEd Maste (uintmax_t) vma);
187676e25abSEd Maste start = vma - (s->vma - s->seg->vaddr);
188a85fe12eSEd Maste if (s == s->seg->v_sec[s->seg->nsec - 1])
189a85fe12eSEd Maste end = start + s->seg->msz;
190a85fe12eSEd Maste else
191676e25abSEd Maste end = s->seg->vaddr + s->seg->msz;
192a85fe12eSEd Maste } else {
193a85fe12eSEd Maste /* Move section to upper address. */
194a85fe12eSEd Maste if (s == s->seg->v_sec[0])
195676e25abSEd Maste start = vma;
196a85fe12eSEd Maste else
197676e25abSEd Maste start = s->seg->vaddr;
198676e25abSEd Maste end = vma + (s->seg->vaddr + s->seg->msz - s->vma);
199a85fe12eSEd Maste if (end < start)
200a85fe12eSEd Maste errx(EXIT_FAILURE, "Not enough space to move "
201676e25abSEd Maste "section %s VMA to %#jx", s->name,
202676e25abSEd Maste (uintmax_t) vma);
203a85fe12eSEd Maste }
204a85fe12eSEd Maste
205a85fe12eSEd Maste #ifdef DEBUG
206a85fe12eSEd Maste printf("new extent for segment containing %s: (%#jx,%#jx)\n",
207a85fe12eSEd Maste s->name, start, end);
208a85fe12eSEd Maste #endif
209a85fe12eSEd Maste
210a85fe12eSEd Maste STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
211a85fe12eSEd Maste if (seg == s->seg || seg->type != PT_LOAD)
212a85fe12eSEd Maste continue;
213676e25abSEd Maste if (start > seg->vaddr + seg->msz)
214a85fe12eSEd Maste continue;
215676e25abSEd Maste if (end < seg->vaddr)
216a85fe12eSEd Maste continue;
217a85fe12eSEd Maste errx(EXIT_FAILURE, "The extent of segment containing "
218a85fe12eSEd Maste "section %s overlaps with segment(%#jx,%#jx)",
219676e25abSEd Maste s->name, (uintmax_t) seg->vaddr,
220676e25abSEd Maste (uintmax_t) (seg->vaddr + seg->msz));
221a85fe12eSEd Maste }
222a85fe12eSEd Maste
223a85fe12eSEd Maste /*
224676e25abSEd Maste * Update section VMA and file offset.
225a85fe12eSEd Maste */
226a85fe12eSEd Maste
227676e25abSEd Maste if (vma < s->vma) {
228a85fe12eSEd Maste /*
229676e25abSEd Maste * To move a section to lower VMA, we decrease
230676e25abSEd Maste * the VMA of the section and all the sections that
231676e25abSEd Maste * are before it, and we increase the file offsets
232676e25abSEd Maste * of all the sections that are after it.
233a85fe12eSEd Maste */
234676e25abSEd Maste dl = s->vma - vma;
235a85fe12eSEd Maste for (i = 0; i < s->seg->nsec; i++) {
236a85fe12eSEd Maste s0 = s->seg->v_sec[i];
237676e25abSEd Maste s0->vma -= dl;
238a85fe12eSEd Maste #ifdef DEBUG
239676e25abSEd Maste printf("section %s VMA set to %#jx\n",
240676e25abSEd Maste s0->name, (uintmax_t) s0->vma);
241a85fe12eSEd Maste #endif
242a85fe12eSEd Maste if (s0 == s)
243a85fe12eSEd Maste break;
244a85fe12eSEd Maste }
245a85fe12eSEd Maste for (i = i + 1; i < s->seg->nsec; i++) {
246a85fe12eSEd Maste s0 = s->seg->v_sec[i];
247a85fe12eSEd Maste s0->off += dl;
248a85fe12eSEd Maste #ifdef DEBUG
249a85fe12eSEd Maste printf("section %s offset set to %#jx\n",
250a85fe12eSEd Maste s0->name, (uintmax_t) s0->off);
251a85fe12eSEd Maste #endif
252a85fe12eSEd Maste }
253a85fe12eSEd Maste } else {
254a85fe12eSEd Maste /*
255676e25abSEd Maste * To move a section to upper VMA, we increase
256676e25abSEd Maste * the VMA of the section and all the sections that
257676e25abSEd Maste * are after it, and we increase the their file
258676e25abSEd Maste * offsets too unless the section in question
259a85fe12eSEd Maste * is the first in its containing segment.
260a85fe12eSEd Maste */
261676e25abSEd Maste dl = vma - s->vma;
262a85fe12eSEd Maste for (i = 0; i < s->seg->nsec; i++)
263a85fe12eSEd Maste if (s->seg->v_sec[i] == s)
264a85fe12eSEd Maste break;
265a85fe12eSEd Maste if (i >= s->seg->nsec)
266a85fe12eSEd Maste errx(EXIT_FAILURE, "Internal: section `%s' not"
267a85fe12eSEd Maste " found in its containing segement",
268a85fe12eSEd Maste s->name);
269a85fe12eSEd Maste for (; i < s->seg->nsec; i++) {
270a85fe12eSEd Maste s0 = s->seg->v_sec[i];
271676e25abSEd Maste s0->vma += dl;
272a85fe12eSEd Maste #ifdef DEBUG
273676e25abSEd Maste printf("section %s VMA set to %#jx\n",
274a85fe12eSEd Maste s0->name, (uintmax_t) s0->lma);
275a85fe12eSEd Maste #endif
276a85fe12eSEd Maste if (s != s->seg->v_sec[0]) {
277a85fe12eSEd Maste s0->off += dl;
278a85fe12eSEd Maste #ifdef DEBUG
279a85fe12eSEd Maste printf("section %s offset set to %#jx\n",
280a85fe12eSEd Maste s0->name, (uintmax_t) s0->off);
281a85fe12eSEd Maste #endif
282a85fe12eSEd Maste }
283a85fe12eSEd Maste }
284a85fe12eSEd Maste }
285a85fe12eSEd Maste }
286a85fe12eSEd Maste
287a85fe12eSEd Maste /*
288a85fe12eSEd Maste * Apply load address padding.
289a85fe12eSEd Maste */
290a85fe12eSEd Maste
291a85fe12eSEd Maste if (ecp->pad_to != 0) {
292a85fe12eSEd Maste
293a85fe12eSEd Maste /*
294676e25abSEd Maste * Find the section with highest VMA.
295a85fe12eSEd Maste */
296a85fe12eSEd Maste s = NULL;
297a85fe12eSEd Maste STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
298a85fe12eSEd Maste if (seg->type != PT_LOAD)
299a85fe12eSEd Maste continue;
300a85fe12eSEd Maste for (i = seg->nsec - 1; i >= 0; i--)
301a85fe12eSEd Maste if (seg->v_sec[i]->type != SHT_NOBITS)
302a85fe12eSEd Maste break;
303a85fe12eSEd Maste if (i < 0)
304a85fe12eSEd Maste continue;
305a85fe12eSEd Maste if (s == NULL)
306a85fe12eSEd Maste s = seg->v_sec[i];
307a85fe12eSEd Maste else {
308a85fe12eSEd Maste s0 = seg->v_sec[i];
309676e25abSEd Maste if (s0->vma > s->vma)
310a85fe12eSEd Maste s = s0;
311a85fe12eSEd Maste }
312a85fe12eSEd Maste }
313a85fe12eSEd Maste
314a85fe12eSEd Maste if (s == NULL)
315676e25abSEd Maste goto adjust_lma;
316a85fe12eSEd Maste
317a85fe12eSEd Maste /* No need to pad if the pad_to address is lower. */
318676e25abSEd Maste if (ecp->pad_to <= s->vma + s->sz)
319676e25abSEd Maste goto adjust_lma;
320a85fe12eSEd Maste
321676e25abSEd Maste s->pad_sz = ecp->pad_to - (s->vma + s->sz);
322a85fe12eSEd Maste #ifdef DEBUG
323676e25abSEd Maste printf("pad section %s VMA to address %#jx by %#jx\n", s->name,
324a85fe12eSEd Maste (uintmax_t) ecp->pad_to, (uintmax_t) s->pad_sz);
325a85fe12eSEd Maste #endif
326a85fe12eSEd Maste }
327a85fe12eSEd Maste
328676e25abSEd Maste
329676e25abSEd Maste adjust_lma:
330676e25abSEd Maste
331676e25abSEd Maste /*
332676e25abSEd Maste * Apply sections LMA change in the third iteration.
333676e25abSEd Maste */
334676e25abSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
335676e25abSEd Maste
336676e25abSEd Maste /*
337676e25abSEd Maste * Only loadable section that's inside a segment can have
338676e25abSEd Maste * LMA adjusted. Also, if LMA of the containing segment is
339676e25abSEd Maste * set to 0, it probably means we should ignore the LMA.
340676e25abSEd Maste */
341676e25abSEd Maste if (!s->loadable || s->seg == NULL || s->seg->paddr == 0)
342676e25abSEd Maste continue;
343676e25abSEd Maste
344676e25abSEd Maste /*
345676e25abSEd Maste * Check if there is a LMA change request for this
346676e25abSEd Maste * section.
347676e25abSEd Maste */
348676e25abSEd Maste sac = lookup_sec_act(ecp, s->name, 0);
349676e25abSEd Maste if (sac == NULL)
350676e25abSEd Maste continue;
351676e25abSEd Maste if (!sac->setlma && sac->lma_adjust == 0)
352676e25abSEd Maste continue;
353676e25abSEd Maste lma = s->lma;
354676e25abSEd Maste if (sac->setlma)
355676e25abSEd Maste lma = sac->lma;
356676e25abSEd Maste if (sac->lma_adjust != 0)
357676e25abSEd Maste lma += sac->lma_adjust;
358676e25abSEd Maste if (lma == s->lma)
359676e25abSEd Maste continue;
360676e25abSEd Maste
361676e25abSEd Maste #ifdef DEBUG
362676e25abSEd Maste printf("LMA for section %s: %#jx\n", s->name, lma);
363676e25abSEd Maste #endif
364676e25abSEd Maste
365676e25abSEd Maste /* Check alignment. */
366676e25abSEd Maste if (lma % s->align != 0)
367676e25abSEd Maste errx(EXIT_FAILURE, "The LMA %#jx for "
368676e25abSEd Maste "section %s is not aligned to %ju",
369676e25abSEd Maste (uintmax_t) lma, s->name, (uintmax_t) s->align);
370676e25abSEd Maste
371676e25abSEd Maste /*
372676e25abSEd Maste * Update section LMA.
373676e25abSEd Maste */
374676e25abSEd Maste
375676e25abSEd Maste if (lma < s->lma) {
376676e25abSEd Maste /*
377676e25abSEd Maste * To move a section to lower LMA, we decrease
378676e25abSEd Maste * the LMA of the section and all the sections that
379676e25abSEd Maste * are before it.
380676e25abSEd Maste */
381676e25abSEd Maste dl = s->lma - lma;
382676e25abSEd Maste for (i = 0; i < s->seg->nsec; i++) {
383676e25abSEd Maste s0 = s->seg->v_sec[i];
384676e25abSEd Maste s0->lma -= dl;
385676e25abSEd Maste #ifdef DEBUG
386676e25abSEd Maste printf("section %s LMA set to %#jx\n",
387676e25abSEd Maste s0->name, (uintmax_t) s0->lma);
388676e25abSEd Maste #endif
389676e25abSEd Maste if (s0 == s)
390676e25abSEd Maste break;
391676e25abSEd Maste }
392676e25abSEd Maste } else {
393676e25abSEd Maste /*
394676e25abSEd Maste * To move a section to upper LMA, we increase
395676e25abSEd Maste * the LMA of the section and all the sections that
396676e25abSEd Maste * are after it.
397676e25abSEd Maste */
398676e25abSEd Maste dl = lma - s->lma;
399676e25abSEd Maste for (i = 0; i < s->seg->nsec; i++)
400676e25abSEd Maste if (s->seg->v_sec[i] == s)
401676e25abSEd Maste break;
402676e25abSEd Maste if (i >= s->seg->nsec)
403676e25abSEd Maste errx(EXIT_FAILURE, "Internal: section `%s' not"
404676e25abSEd Maste " found in its containing segement",
405676e25abSEd Maste s->name);
406676e25abSEd Maste for (; i < s->seg->nsec; i++) {
407676e25abSEd Maste s0 = s->seg->v_sec[i];
408676e25abSEd Maste s0->lma += dl;
409676e25abSEd Maste #ifdef DEBUG
410676e25abSEd Maste printf("section %s LMA set to %#jx\n",
411676e25abSEd Maste s0->name, (uintmax_t) s0->lma);
412676e25abSEd Maste #endif
413676e25abSEd Maste }
414676e25abSEd Maste }
415676e25abSEd Maste }
416a85fe12eSEd Maste
417a85fe12eSEd Maste /*
418a85fe12eSEd Maste * Issue a warning if there are VMA/LMA adjust requests for
419a85fe12eSEd Maste * some nonexistent sections.
420a85fe12eSEd Maste */
421a85fe12eSEd Maste if ((ecp->flags & NO_CHANGE_WARN) == 0) {
422a85fe12eSEd Maste STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
423a85fe12eSEd Maste if (!sac->setvma && !sac->setlma &&
424a85fe12eSEd Maste !sac->vma_adjust && !sac->lma_adjust)
425a85fe12eSEd Maste continue;
426a85fe12eSEd Maste found = 0;
427a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
428a85fe12eSEd Maste if (s->pseudo || s->name == NULL)
429a85fe12eSEd Maste continue;
430a85fe12eSEd Maste if (!strcmp(s->name, sac->name)) {
431a85fe12eSEd Maste found = 1;
432a85fe12eSEd Maste break;
433a85fe12eSEd Maste }
434a85fe12eSEd Maste }
435a85fe12eSEd Maste if (!found)
436a85fe12eSEd Maste warnx("cannot find section `%s'", sac->name);
437a85fe12eSEd Maste }
438a85fe12eSEd Maste }
439a85fe12eSEd Maste }
440a85fe12eSEd Maste
441a85fe12eSEd Maste static void
insert_to_inseg_list(struct segment * seg,struct section * sec)442a85fe12eSEd Maste insert_to_inseg_list(struct segment *seg, struct section *sec)
443a85fe12eSEd Maste {
444a85fe12eSEd Maste struct section *s;
445a85fe12eSEd Maste int i;
446a85fe12eSEd Maste
447a85fe12eSEd Maste seg->nsec++;
448a85fe12eSEd Maste seg->v_sec = realloc(seg->v_sec, seg->nsec * sizeof(*seg->v_sec));
449a85fe12eSEd Maste if (seg->v_sec == NULL)
450a85fe12eSEd Maste err(EXIT_FAILURE, "realloc failed");
451a85fe12eSEd Maste
452a85fe12eSEd Maste /*
453a85fe12eSEd Maste * Sort the section in order of offset.
454a85fe12eSEd Maste */
455a85fe12eSEd Maste
456a85fe12eSEd Maste for (i = seg->nsec - 1; i > 0; i--) {
457a85fe12eSEd Maste s = seg->v_sec[i - 1];
458a85fe12eSEd Maste if (sec->off >= s->off) {
459a85fe12eSEd Maste seg->v_sec[i] = sec;
460a85fe12eSEd Maste break;
461a85fe12eSEd Maste } else
462a85fe12eSEd Maste seg->v_sec[i] = s;
463a85fe12eSEd Maste }
464a85fe12eSEd Maste if (i == 0)
465a85fe12eSEd Maste seg->v_sec[0] = sec;
466a85fe12eSEd Maste }
467a85fe12eSEd Maste
468a85fe12eSEd Maste void
setup_phdr(struct elfcopy * ecp)469a85fe12eSEd Maste setup_phdr(struct elfcopy *ecp)
470a85fe12eSEd Maste {
471a85fe12eSEd Maste struct segment *seg;
472a85fe12eSEd Maste GElf_Phdr iphdr;
473b6b6f9ccSEd Maste size_t iphnum, i;
474a85fe12eSEd Maste
475a85fe12eSEd Maste if (elf_getphnum(ecp->ein, &iphnum) == 0)
476a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_getphnum failed: %s",
477a85fe12eSEd Maste elf_errmsg(-1));
478a85fe12eSEd Maste
479a85fe12eSEd Maste ecp->ophnum = ecp->iphnum = iphnum;
480a85fe12eSEd Maste if (iphnum == 0)
481a85fe12eSEd Maste return;
482a85fe12eSEd Maste
483a85fe12eSEd Maste /* If --only-keep-debug is specified, discard all program headers. */
484a85fe12eSEd Maste if (ecp->strip == STRIP_NONDEBUG) {
485a85fe12eSEd Maste ecp->ophnum = 0;
486a85fe12eSEd Maste return;
487a85fe12eSEd Maste }
488a85fe12eSEd Maste
489b6b6f9ccSEd Maste for (i = 0; i < iphnum; i++) {
490a85fe12eSEd Maste if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
491a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
492a85fe12eSEd Maste elf_errmsg(-1));
493a85fe12eSEd Maste if ((seg = calloc(1, sizeof(*seg))) == NULL)
494a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed");
495676e25abSEd Maste seg->vaddr = iphdr.p_vaddr;
496676e25abSEd Maste seg->paddr = iphdr.p_paddr;
497a85fe12eSEd Maste seg->off = iphdr.p_offset;
498a85fe12eSEd Maste seg->fsz = iphdr.p_filesz;
499a85fe12eSEd Maste seg->msz = iphdr.p_memsz;
500a85fe12eSEd Maste seg->type = iphdr.p_type;
501a85fe12eSEd Maste STAILQ_INSERT_TAIL(&ecp->v_seg, seg, seg_list);
502a85fe12eSEd Maste }
503a85fe12eSEd Maste }
504a85fe12eSEd Maste
505a85fe12eSEd Maste void
copy_phdr(struct elfcopy * ecp)506a85fe12eSEd Maste copy_phdr(struct elfcopy *ecp)
507a85fe12eSEd Maste {
508a85fe12eSEd Maste struct segment *seg;
509a85fe12eSEd Maste struct section *s;
510a85fe12eSEd Maste GElf_Phdr iphdr, ophdr;
511a85fe12eSEd Maste int i;
512a85fe12eSEd Maste
513a85fe12eSEd Maste STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
514a85fe12eSEd Maste if (seg->type == PT_PHDR) {
515a85fe12eSEd Maste if (!TAILQ_EMPTY(&ecp->v_sec)) {
516a85fe12eSEd Maste s = TAILQ_FIRST(&ecp->v_sec);
517676e25abSEd Maste if (s->pseudo) {
518676e25abSEd Maste seg->vaddr = s->vma +
519a85fe12eSEd Maste gelf_fsize(ecp->eout, ELF_T_EHDR,
520a85fe12eSEd Maste 1, EV_CURRENT);
521676e25abSEd Maste seg->paddr = s->lma +
522676e25abSEd Maste gelf_fsize(ecp->eout, ELF_T_EHDR,
523676e25abSEd Maste 1, EV_CURRENT);
524676e25abSEd Maste }
525a85fe12eSEd Maste }
526a85fe12eSEd Maste seg->fsz = seg->msz = gelf_fsize(ecp->eout, ELF_T_PHDR,
527a85fe12eSEd Maste ecp->ophnum, EV_CURRENT);
528a85fe12eSEd Maste continue;
529a85fe12eSEd Maste }
530a85fe12eSEd Maste
531676e25abSEd Maste if (seg->nsec > 0) {
532676e25abSEd Maste s = seg->v_sec[0];
533676e25abSEd Maste seg->vaddr = s->vma;
534676e25abSEd Maste seg->paddr = s->lma;
535676e25abSEd Maste }
536676e25abSEd Maste
537a85fe12eSEd Maste seg->fsz = seg->msz = 0;
538a85fe12eSEd Maste for (i = 0; i < seg->nsec; i++) {
539a85fe12eSEd Maste s = seg->v_sec[i];
540676e25abSEd Maste seg->msz = s->vma + s->sz - seg->vaddr;
541a85fe12eSEd Maste if (s->type != SHT_NOBITS)
542b00fe64fSEd Maste seg->fsz = s->off + s->sz - seg->off;
543a85fe12eSEd Maste }
544a85fe12eSEd Maste }
545a85fe12eSEd Maste
546a85fe12eSEd Maste /*
547a85fe12eSEd Maste * Allocate space for program headers, note that libelf keep
548a85fe12eSEd Maste * track of the number in internal variable, and a call to
549a85fe12eSEd Maste * elf_update is needed to update e_phnum of ehdr.
550a85fe12eSEd Maste */
551a85fe12eSEd Maste if (gelf_newphdr(ecp->eout, ecp->ophnum) == NULL)
552a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_newphdr() failed: %s",
553a85fe12eSEd Maste elf_errmsg(-1));
554a85fe12eSEd Maste
555a85fe12eSEd Maste /*
556a85fe12eSEd Maste * This elf_update() call is to update the e_phnum field in
557a85fe12eSEd Maste * ehdr. It's necessary because later we will call gelf_getphdr(),
558a85fe12eSEd Maste * which does sanity check by comparing ndx argument with e_phnum.
559a85fe12eSEd Maste */
560a85fe12eSEd Maste if (elf_update(ecp->eout, ELF_C_NULL) < 0)
561a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1));
562a85fe12eSEd Maste
563a85fe12eSEd Maste /*
564a85fe12eSEd Maste * iphnum == ophnum, since we don't remove program headers even if
565a85fe12eSEd Maste * they no longer contain sections.
566a85fe12eSEd Maste */
567a85fe12eSEd Maste i = 0;
568a85fe12eSEd Maste STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
569a85fe12eSEd Maste if (i >= ecp->iphnum)
570a85fe12eSEd Maste break;
571a85fe12eSEd Maste if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
572a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
573a85fe12eSEd Maste elf_errmsg(-1));
574a85fe12eSEd Maste if (gelf_getphdr(ecp->eout, i, &ophdr) != &ophdr)
575a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
576a85fe12eSEd Maste elf_errmsg(-1));
577a85fe12eSEd Maste
578a85fe12eSEd Maste ophdr.p_type = iphdr.p_type;
579676e25abSEd Maste ophdr.p_vaddr = seg->vaddr;
580676e25abSEd Maste ophdr.p_paddr = seg->paddr;
581a85fe12eSEd Maste ophdr.p_flags = iphdr.p_flags;
582a85fe12eSEd Maste ophdr.p_align = iphdr.p_align;
583a85fe12eSEd Maste ophdr.p_offset = seg->off;
584a85fe12eSEd Maste ophdr.p_filesz = seg->fsz;
585a85fe12eSEd Maste ophdr.p_memsz = seg->msz;
586a85fe12eSEd Maste if (!gelf_update_phdr(ecp->eout, i, &ophdr))
587839529caSEd Maste errx(EXIT_FAILURE, "gelf_update_phdr failed: %s",
588a85fe12eSEd Maste elf_errmsg(-1));
589a85fe12eSEd Maste
590a85fe12eSEd Maste i++;
591a85fe12eSEd Maste }
592a85fe12eSEd Maste }
593