2 * Copyright (c) 2007-2010,2012 Kai Wang
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/queue.h>
37 ELFTC_VCSID("$Id: segments.c 3449 2016-05-03 13:59:29Z emaste $");
39 static void insert_to_inseg_list(struct segment *seg, struct section *sec);
42 * elfcopy's segment handling is relatively simpler and less powerful than
43 * libbfd. Program headers are modified or copied from input to output objects,
44 * but never re-generated. As a result, if the input object has incorrect
45 * program headers, the output object's program headers will remain incorrect
46 * or become even worse.
50 * Check whether a section is "loadable". If so, add it to the
51 * corresponding segment list(s) and return 1.
54 add_to_inseg_list(struct elfcopy *ecp, struct section *s)
63 * Segment is a different view of an ELF object. One segment can
64 * contain one or more sections, and one section can be included
65 * in one or more segments, or not included in any segment at all.
66 * We call those sections which can be found in one or more segments
67 * "loadable" sections, and call the rest "unloadable" sections.
68 * We keep track of "loadable" sections in their containing
69 * segment(s)' v_sec queue. These information are later used to
70 * recalculate the extents of segments, when sections are removed,
74 STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
75 if (s->off < seg->off || (s->vma < seg->vaddr && !s->pseudo))
77 if (s->off + s->sz > seg->off + seg->fsz &&
78 s->type != SHT_NOBITS)
80 if (s->vma + s->sz > seg->vaddr + seg->msz)
83 insert_to_inseg_list(seg, s);
84 if (seg->type == PT_LOAD)
86 else if (seg->type == PT_TLS)
89 s->vma = seg->vaddr + (s->off - seg->off);
91 s->lma = seg->paddr + (s->off - seg->off);
101 adjust_addr(struct elfcopy *ecp)
103 struct section *s, *s0;
105 struct sec_action *sac;
106 uint64_t dl, vma, lma, start, end;
110 * Apply VMA and global LMA changes in the first iteration.
112 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
114 /* Only adjust loadable section's address. */
118 /* Apply global VMA adjustment. */
119 if (ecp->change_addr != 0)
120 s->vma += ecp->change_addr;
122 /* Apply global LMA adjustment. */
123 if (ecp->change_addr != 0 && s->seg != NULL &&
125 s->lma += ecp->change_addr;
129 * Apply sections VMA change in the second iteration.
131 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
137 * Check if there is a VMA change request for this
140 sac = lookup_sec_act(ecp, s->name, 0);
146 if (sac->vma_adjust != 0)
147 vma += sac->vma_adjust;
152 * No need to make segment adjustment if the section doesn't
153 * belong to any segment.
155 if (s->seg == NULL) {
161 * Check if the VMA change is viable.
163 * 1. Check if the new VMA is properly aligned accroding to
166 * 2. Compute the new extent of segment that contains this
167 * section, make sure it doesn't overlap with other
171 printf("VMA for section %s: %#jx\n", s->name, vma);
174 if (vma % s->align != 0)
175 errx(EXIT_FAILURE, "The VMA %#jx for "
176 "section %s is not aligned to %ju",
177 (uintmax_t) vma, s->name, (uintmax_t) s->align);
180 /* Move section to lower address. */
181 if (vma < s->vma - s->seg->vaddr)
182 errx(EXIT_FAILURE, "Not enough space to move "
183 "section %s VMA to %#jx", s->name,
185 start = vma - (s->vma - s->seg->vaddr);
186 if (s == s->seg->v_sec[s->seg->nsec - 1])
187 end = start + s->seg->msz;
189 end = s->seg->vaddr + s->seg->msz;
191 /* Move section to upper address. */
192 if (s == s->seg->v_sec[0])
195 start = s->seg->vaddr;
196 end = vma + (s->seg->vaddr + s->seg->msz - s->vma);
198 errx(EXIT_FAILURE, "Not enough space to move "
199 "section %s VMA to %#jx", s->name,
204 printf("new extent for segment containing %s: (%#jx,%#jx)\n",
205 s->name, start, end);
208 STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
209 if (seg == s->seg || seg->type != PT_LOAD)
211 if (start > seg->vaddr + seg->msz)
213 if (end < seg->vaddr)
215 errx(EXIT_FAILURE, "The extent of segment containing "
216 "section %s overlaps with segment(%#jx,%#jx)",
217 s->name, (uintmax_t) seg->vaddr,
218 (uintmax_t) (seg->vaddr + seg->msz));
222 * Update section VMA and file offset.
227 * To move a section to lower VMA, we decrease
228 * the VMA of the section and all the sections that
229 * are before it, and we increase the file offsets
230 * of all the sections that are after it.
233 for (i = 0; i < s->seg->nsec; i++) {
234 s0 = s->seg->v_sec[i];
237 printf("section %s VMA set to %#jx\n",
238 s0->name, (uintmax_t) s0->vma);
243 for (i = i + 1; i < s->seg->nsec; i++) {
244 s0 = s->seg->v_sec[i];
247 printf("section %s offset set to %#jx\n",
248 s0->name, (uintmax_t) s0->off);
253 * To move a section to upper VMA, we increase
254 * the VMA of the section and all the sections that
255 * are after it, and we increase the their file
256 * offsets too unless the section in question
257 * is the first in its containing segment.
260 for (i = 0; i < s->seg->nsec; i++)
261 if (s->seg->v_sec[i] == s)
263 if (i >= s->seg->nsec)
264 errx(EXIT_FAILURE, "Internal: section `%s' not"
265 " found in its containing segement",
267 for (; i < s->seg->nsec; i++) {
268 s0 = s->seg->v_sec[i];
271 printf("section %s VMA set to %#jx\n",
272 s0->name, (uintmax_t) s0->lma);
274 if (s != s->seg->v_sec[0]) {
277 printf("section %s offset set to %#jx\n",
278 s0->name, (uintmax_t) s0->off);
286 * Apply load address padding.
289 if (ecp->pad_to != 0) {
292 * Find the section with highest VMA.
295 STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
296 if (seg->type != PT_LOAD)
298 for (i = seg->nsec - 1; i >= 0; i--)
299 if (seg->v_sec[i]->type != SHT_NOBITS)
307 if (s0->vma > s->vma)
315 /* No need to pad if the pad_to address is lower. */
316 if (ecp->pad_to <= s->vma + s->sz)
319 s->pad_sz = ecp->pad_to - (s->vma + s->sz);
321 printf("pad section %s VMA to address %#jx by %#jx\n", s->name,
322 (uintmax_t) ecp->pad_to, (uintmax_t) s->pad_sz);
330 * Apply sections LMA change in the third iteration.
332 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
335 * Only loadable section that's inside a segment can have
336 * LMA adjusted. Also, if LMA of the containing segment is
337 * set to 0, it probably means we should ignore the LMA.
339 if (!s->loadable || s->seg == NULL || s->seg->paddr == 0)
343 * Check if there is a LMA change request for this
346 sac = lookup_sec_act(ecp, s->name, 0);
349 if (!sac->setlma && sac->lma_adjust == 0)
354 if (sac->lma_adjust != 0)
355 lma += sac->lma_adjust;
360 printf("LMA for section %s: %#jx\n", s->name, lma);
363 /* Check alignment. */
364 if (lma % s->align != 0)
365 errx(EXIT_FAILURE, "The LMA %#jx for "
366 "section %s is not aligned to %ju",
367 (uintmax_t) lma, s->name, (uintmax_t) s->align);
370 * Update section LMA.
375 * To move a section to lower LMA, we decrease
376 * the LMA of the section and all the sections that
380 for (i = 0; i < s->seg->nsec; i++) {
381 s0 = s->seg->v_sec[i];
384 printf("section %s LMA set to %#jx\n",
385 s0->name, (uintmax_t) s0->lma);
392 * To move a section to upper LMA, we increase
393 * the LMA of the section and all the sections that
397 for (i = 0; i < s->seg->nsec; i++)
398 if (s->seg->v_sec[i] == s)
400 if (i >= s->seg->nsec)
401 errx(EXIT_FAILURE, "Internal: section `%s' not"
402 " found in its containing segement",
404 for (; i < s->seg->nsec; i++) {
405 s0 = s->seg->v_sec[i];
408 printf("section %s LMA set to %#jx\n",
409 s0->name, (uintmax_t) s0->lma);
416 * Issue a warning if there are VMA/LMA adjust requests for
417 * some nonexistent sections.
419 if ((ecp->flags & NO_CHANGE_WARN) == 0) {
420 STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
421 if (!sac->setvma && !sac->setlma &&
422 !sac->vma_adjust && !sac->lma_adjust)
425 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
426 if (s->pseudo || s->name == NULL)
428 if (!strcmp(s->name, sac->name)) {
434 warnx("cannot find section `%s'", sac->name);
440 insert_to_inseg_list(struct segment *seg, struct section *sec)
446 seg->v_sec = realloc(seg->v_sec, seg->nsec * sizeof(*seg->v_sec));
447 if (seg->v_sec == NULL)
448 err(EXIT_FAILURE, "realloc failed");
451 * Sort the section in order of offset.
454 for (i = seg->nsec - 1; i > 0; i--) {
455 s = seg->v_sec[i - 1];
456 if (sec->off >= s->off) {
467 setup_phdr(struct elfcopy *ecp)
473 if (elf_getphnum(ecp->ein, &iphnum) == 0)
474 errx(EXIT_FAILURE, "elf_getphnum failed: %s",
477 ecp->ophnum = ecp->iphnum = iphnum;
481 /* If --only-keep-debug is specified, discard all program headers. */
482 if (ecp->strip == STRIP_NONDEBUG) {
487 for (i = 0; i < iphnum; i++) {
488 if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
489 errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
491 if ((seg = calloc(1, sizeof(*seg))) == NULL)
492 err(EXIT_FAILURE, "calloc failed");
493 seg->vaddr = iphdr.p_vaddr;
494 seg->paddr = iphdr.p_paddr;
495 seg->off = iphdr.p_offset;
496 seg->fsz = iphdr.p_filesz;
497 seg->msz = iphdr.p_memsz;
498 seg->type = iphdr.p_type;
499 STAILQ_INSERT_TAIL(&ecp->v_seg, seg, seg_list);
504 copy_phdr(struct elfcopy *ecp)
508 GElf_Phdr iphdr, ophdr;
511 STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
512 if (seg->type == PT_PHDR) {
513 if (!TAILQ_EMPTY(&ecp->v_sec)) {
514 s = TAILQ_FIRST(&ecp->v_sec);
516 seg->vaddr = s->vma +
517 gelf_fsize(ecp->eout, ELF_T_EHDR,
519 seg->paddr = s->lma +
520 gelf_fsize(ecp->eout, ELF_T_EHDR,
524 seg->fsz = seg->msz = gelf_fsize(ecp->eout, ELF_T_PHDR,
525 ecp->ophnum, EV_CURRENT);
535 seg->fsz = seg->msz = 0;
536 for (i = 0; i < seg->nsec; i++) {
538 seg->msz = s->vma + s->sz - seg->vaddr;
539 if (s->type != SHT_NOBITS)
540 seg->fsz = s->off + s->sz - seg->off;
545 * Allocate space for program headers, note that libelf keep
546 * track of the number in internal variable, and a call to
547 * elf_update is needed to update e_phnum of ehdr.
549 if (gelf_newphdr(ecp->eout, ecp->ophnum) == NULL)
550 errx(EXIT_FAILURE, "gelf_newphdr() failed: %s",
554 * This elf_update() call is to update the e_phnum field in
555 * ehdr. It's necessary because later we will call gelf_getphdr(),
556 * which does sanity check by comparing ndx argument with e_phnum.
558 if (elf_update(ecp->eout, ELF_C_NULL) < 0)
559 errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1));
562 * iphnum == ophnum, since we don't remove program headers even if
563 * they no longer contain sections.
566 STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
567 if (i >= ecp->iphnum)
569 if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
570 errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
572 if (gelf_getphdr(ecp->eout, i, &ophdr) != &ophdr)
573 errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
576 ophdr.p_type = iphdr.p_type;
577 ophdr.p_vaddr = seg->vaddr;
578 ophdr.p_paddr = seg->paddr;
579 ophdr.p_flags = iphdr.p_flags;
580 ophdr.p_align = iphdr.p_align;
581 ophdr.p_offset = seg->off;
582 ophdr.p_filesz = seg->fsz;
583 ophdr.p_memsz = seg->msz;
584 if (!gelf_update_phdr(ecp->eout, i, &ophdr))
585 errx(EXIT_FAILURE, "gelf_update_phdr failed: %s",