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*b6b6f9ccSEd Maste ELFTC_VCSID("$Id: segments.c 3449 2016-05-03 13:59:29Z emaste $"); 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 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; 82a85fe12eSEd Maste 83a85fe12eSEd Maste insert_to_inseg_list(seg, s); 84a85fe12eSEd Maste if (seg->type == PT_LOAD) 85a85fe12eSEd Maste s->seg = seg; 864a85c691SEd Maste else if (seg->type == PT_TLS) 874a85c691SEd Maste s->seg_tls = seg; 88676e25abSEd Maste if (s->pseudo) 89676e25abSEd Maste s->vma = seg->vaddr + (s->off - seg->off); 90676e25abSEd Maste if (seg->paddr > 0) 91676e25abSEd Maste s->lma = seg->paddr + (s->off - seg->off); 92676e25abSEd Maste else 93676e25abSEd Maste s->lma = 0; 94a85fe12eSEd Maste loadable = 1; 95a85fe12eSEd Maste } 96a85fe12eSEd Maste 97a85fe12eSEd Maste return (loadable); 98a85fe12eSEd Maste } 99a85fe12eSEd Maste 100a85fe12eSEd Maste void 101a85fe12eSEd Maste adjust_addr(struct elfcopy *ecp) 102a85fe12eSEd Maste { 103a85fe12eSEd Maste struct section *s, *s0; 104a85fe12eSEd Maste struct segment *seg; 105a85fe12eSEd Maste struct sec_action *sac; 106676e25abSEd Maste uint64_t dl, vma, lma, start, end; 107a85fe12eSEd Maste int found, i; 108a85fe12eSEd Maste 109a85fe12eSEd Maste /* 110a85fe12eSEd Maste * Apply VMA and global LMA changes in the first iteration. 111a85fe12eSEd Maste */ 112a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 113a85fe12eSEd Maste 114a85fe12eSEd Maste /* Only adjust loadable section's address. */ 115839529caSEd Maste if (!s->loadable) 116a85fe12eSEd Maste continue; 117a85fe12eSEd Maste 118a85fe12eSEd Maste /* Apply global VMA adjustment. */ 119a85fe12eSEd Maste if (ecp->change_addr != 0) 120a85fe12eSEd Maste s->vma += ecp->change_addr; 121a85fe12eSEd Maste 122676e25abSEd Maste /* Apply global LMA adjustment. */ 123676e25abSEd Maste if (ecp->change_addr != 0 && s->seg != NULL && 124676e25abSEd Maste s->seg->paddr > 0) 125676e25abSEd Maste s->lma += ecp->change_addr; 126a85fe12eSEd Maste } 127a85fe12eSEd Maste 128a85fe12eSEd Maste /* 129676e25abSEd Maste * Apply sections VMA change in the second iteration. 130a85fe12eSEd Maste */ 131a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 132a85fe12eSEd Maste 133676e25abSEd Maste if (!s->loadable) 134a85fe12eSEd Maste continue; 135a85fe12eSEd Maste 136a85fe12eSEd Maste /* 137676e25abSEd Maste * Check if there is a VMA change request for this 138a85fe12eSEd Maste * section. 139a85fe12eSEd Maste */ 140a85fe12eSEd Maste sac = lookup_sec_act(ecp, s->name, 0); 141a85fe12eSEd Maste if (sac == NULL) 142a85fe12eSEd Maste continue; 143676e25abSEd Maste vma = s->vma; 144676e25abSEd Maste if (sac->setvma) 145676e25abSEd Maste vma = sac->vma; 146676e25abSEd Maste if (sac->vma_adjust != 0) 147676e25abSEd Maste vma += sac->vma_adjust; 148676e25abSEd Maste if (vma == s->vma) 149a85fe12eSEd Maste continue; 150a85fe12eSEd Maste 151a85fe12eSEd Maste /* 152676e25abSEd Maste * No need to make segment adjustment if the section doesn't 153676e25abSEd Maste * belong to any segment. 154676e25abSEd Maste */ 155676e25abSEd Maste if (s->seg == NULL) { 156676e25abSEd Maste s->vma = vma; 157676e25abSEd Maste continue; 158676e25abSEd Maste } 159676e25abSEd Maste 160676e25abSEd Maste /* 161676e25abSEd Maste * Check if the VMA change is viable. 162a85fe12eSEd Maste * 163676e25abSEd Maste * 1. Check if the new VMA 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 171676e25abSEd Maste printf("VMA for section %s: %#jx\n", s->name, vma); 172a85fe12eSEd Maste #endif 173a85fe12eSEd Maste 174676e25abSEd Maste if (vma % s->align != 0) 175676e25abSEd Maste errx(EXIT_FAILURE, "The VMA %#jx for " 176a85fe12eSEd Maste "section %s is not aligned to %ju", 177676e25abSEd Maste (uintmax_t) vma, s->name, (uintmax_t) s->align); 178a85fe12eSEd Maste 179676e25abSEd Maste if (vma < s->vma) { 180a85fe12eSEd Maste /* Move section to lower address. */ 181676e25abSEd Maste if (vma < s->vma - s->seg->vaddr) 182a85fe12eSEd Maste errx(EXIT_FAILURE, "Not enough space to move " 183676e25abSEd Maste "section %s VMA to %#jx", s->name, 184676e25abSEd Maste (uintmax_t) vma); 185676e25abSEd Maste start = vma - (s->vma - s->seg->vaddr); 186a85fe12eSEd Maste if (s == s->seg->v_sec[s->seg->nsec - 1]) 187a85fe12eSEd Maste end = start + s->seg->msz; 188a85fe12eSEd Maste else 189676e25abSEd Maste end = s->seg->vaddr + s->seg->msz; 190a85fe12eSEd Maste } else { 191a85fe12eSEd Maste /* Move section to upper address. */ 192a85fe12eSEd Maste if (s == s->seg->v_sec[0]) 193676e25abSEd Maste start = vma; 194a85fe12eSEd Maste else 195676e25abSEd Maste start = s->seg->vaddr; 196676e25abSEd Maste end = vma + (s->seg->vaddr + s->seg->msz - s->vma); 197a85fe12eSEd Maste if (end < start) 198a85fe12eSEd Maste errx(EXIT_FAILURE, "Not enough space to move " 199676e25abSEd Maste "section %s VMA to %#jx", s->name, 200676e25abSEd Maste (uintmax_t) vma); 201a85fe12eSEd Maste } 202a85fe12eSEd Maste 203a85fe12eSEd Maste #ifdef DEBUG 204a85fe12eSEd Maste printf("new extent for segment containing %s: (%#jx,%#jx)\n", 205a85fe12eSEd Maste s->name, start, end); 206a85fe12eSEd Maste #endif 207a85fe12eSEd Maste 208a85fe12eSEd Maste STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { 209a85fe12eSEd Maste if (seg == s->seg || seg->type != PT_LOAD) 210a85fe12eSEd Maste continue; 211676e25abSEd Maste if (start > seg->vaddr + seg->msz) 212a85fe12eSEd Maste continue; 213676e25abSEd Maste if (end < seg->vaddr) 214a85fe12eSEd Maste continue; 215a85fe12eSEd Maste errx(EXIT_FAILURE, "The extent of segment containing " 216a85fe12eSEd Maste "section %s overlaps with segment(%#jx,%#jx)", 217676e25abSEd Maste s->name, (uintmax_t) seg->vaddr, 218676e25abSEd Maste (uintmax_t) (seg->vaddr + seg->msz)); 219a85fe12eSEd Maste } 220a85fe12eSEd Maste 221a85fe12eSEd Maste /* 222676e25abSEd Maste * Update section VMA and file offset. 223a85fe12eSEd Maste */ 224a85fe12eSEd Maste 225676e25abSEd Maste if (vma < s->vma) { 226a85fe12eSEd Maste /* 227676e25abSEd Maste * To move a section to lower VMA, we decrease 228676e25abSEd Maste * the VMA of the section and all the sections that 229676e25abSEd Maste * are before it, and we increase the file offsets 230676e25abSEd Maste * of all the sections that are after it. 231a85fe12eSEd Maste */ 232676e25abSEd Maste dl = s->vma - vma; 233a85fe12eSEd Maste for (i = 0; i < s->seg->nsec; i++) { 234a85fe12eSEd Maste s0 = s->seg->v_sec[i]; 235676e25abSEd Maste s0->vma -= dl; 236a85fe12eSEd Maste #ifdef DEBUG 237676e25abSEd Maste printf("section %s VMA set to %#jx\n", 238676e25abSEd Maste s0->name, (uintmax_t) s0->vma); 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 /* 253676e25abSEd Maste * To move a section to upper VMA, we increase 254676e25abSEd Maste * the VMA of the section and all the sections that 255676e25abSEd Maste * are after it, and we increase the their file 256676e25abSEd Maste * offsets too unless the section in question 257a85fe12eSEd Maste * is the first in its containing segment. 258a85fe12eSEd Maste */ 259676e25abSEd Maste dl = vma - s->vma; 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]; 269676e25abSEd Maste s0->vma += dl; 270a85fe12eSEd Maste #ifdef DEBUG 271676e25abSEd Maste printf("section %s VMA 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 /* 292676e25abSEd Maste * Find the section with highest VMA. 293a85fe12eSEd Maste */ 294a85fe12eSEd Maste s = NULL; 295a85fe12eSEd Maste STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { 296a85fe12eSEd Maste if (seg->type != PT_LOAD) 297a85fe12eSEd Maste continue; 298a85fe12eSEd Maste for (i = seg->nsec - 1; i >= 0; i--) 299a85fe12eSEd Maste if (seg->v_sec[i]->type != SHT_NOBITS) 300a85fe12eSEd Maste break; 301a85fe12eSEd Maste if (i < 0) 302a85fe12eSEd Maste continue; 303a85fe12eSEd Maste if (s == NULL) 304a85fe12eSEd Maste s = seg->v_sec[i]; 305a85fe12eSEd Maste else { 306a85fe12eSEd Maste s0 = seg->v_sec[i]; 307676e25abSEd Maste if (s0->vma > s->vma) 308a85fe12eSEd Maste s = s0; 309a85fe12eSEd Maste } 310a85fe12eSEd Maste } 311a85fe12eSEd Maste 312a85fe12eSEd Maste if (s == NULL) 313676e25abSEd Maste goto adjust_lma; 314a85fe12eSEd Maste 315a85fe12eSEd Maste /* No need to pad if the pad_to address is lower. */ 316676e25abSEd Maste if (ecp->pad_to <= s->vma + s->sz) 317676e25abSEd Maste goto adjust_lma; 318a85fe12eSEd Maste 319676e25abSEd Maste s->pad_sz = ecp->pad_to - (s->vma + s->sz); 320a85fe12eSEd Maste #ifdef DEBUG 321676e25abSEd Maste printf("pad section %s VMA to address %#jx by %#jx\n", s->name, 322a85fe12eSEd Maste (uintmax_t) ecp->pad_to, (uintmax_t) s->pad_sz); 323a85fe12eSEd Maste #endif 324a85fe12eSEd Maste } 325a85fe12eSEd Maste 326676e25abSEd Maste 327676e25abSEd Maste adjust_lma: 328676e25abSEd Maste 329676e25abSEd Maste /* 330676e25abSEd Maste * Apply sections LMA change in the third iteration. 331676e25abSEd Maste */ 332676e25abSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 333676e25abSEd Maste 334676e25abSEd Maste /* 335676e25abSEd Maste * Only loadable section that's inside a segment can have 336676e25abSEd Maste * LMA adjusted. Also, if LMA of the containing segment is 337676e25abSEd Maste * set to 0, it probably means we should ignore the LMA. 338676e25abSEd Maste */ 339676e25abSEd Maste if (!s->loadable || s->seg == NULL || s->seg->paddr == 0) 340676e25abSEd Maste continue; 341676e25abSEd Maste 342676e25abSEd Maste /* 343676e25abSEd Maste * Check if there is a LMA change request for this 344676e25abSEd Maste * section. 345676e25abSEd Maste */ 346676e25abSEd Maste sac = lookup_sec_act(ecp, s->name, 0); 347676e25abSEd Maste if (sac == NULL) 348676e25abSEd Maste continue; 349676e25abSEd Maste if (!sac->setlma && sac->lma_adjust == 0) 350676e25abSEd Maste continue; 351676e25abSEd Maste lma = s->lma; 352676e25abSEd Maste if (sac->setlma) 353676e25abSEd Maste lma = sac->lma; 354676e25abSEd Maste if (sac->lma_adjust != 0) 355676e25abSEd Maste lma += sac->lma_adjust; 356676e25abSEd Maste if (lma == s->lma) 357676e25abSEd Maste continue; 358676e25abSEd Maste 359676e25abSEd Maste #ifdef DEBUG 360676e25abSEd Maste printf("LMA for section %s: %#jx\n", s->name, lma); 361676e25abSEd Maste #endif 362676e25abSEd Maste 363676e25abSEd Maste /* Check alignment. */ 364676e25abSEd Maste if (lma % s->align != 0) 365676e25abSEd Maste errx(EXIT_FAILURE, "The LMA %#jx for " 366676e25abSEd Maste "section %s is not aligned to %ju", 367676e25abSEd Maste (uintmax_t) lma, s->name, (uintmax_t) s->align); 368676e25abSEd Maste 369676e25abSEd Maste /* 370676e25abSEd Maste * Update section LMA. 371676e25abSEd Maste */ 372676e25abSEd Maste 373676e25abSEd Maste if (lma < s->lma) { 374676e25abSEd Maste /* 375676e25abSEd Maste * To move a section to lower LMA, we decrease 376676e25abSEd Maste * the LMA of the section and all the sections that 377676e25abSEd Maste * are before it. 378676e25abSEd Maste */ 379676e25abSEd Maste dl = s->lma - lma; 380676e25abSEd Maste for (i = 0; i < s->seg->nsec; i++) { 381676e25abSEd Maste s0 = s->seg->v_sec[i]; 382676e25abSEd Maste s0->lma -= dl; 383676e25abSEd Maste #ifdef DEBUG 384676e25abSEd Maste printf("section %s LMA set to %#jx\n", 385676e25abSEd Maste s0->name, (uintmax_t) s0->lma); 386676e25abSEd Maste #endif 387676e25abSEd Maste if (s0 == s) 388676e25abSEd Maste break; 389676e25abSEd Maste } 390676e25abSEd Maste } else { 391676e25abSEd Maste /* 392676e25abSEd Maste * To move a section to upper LMA, we increase 393676e25abSEd Maste * the LMA of the section and all the sections that 394676e25abSEd Maste * are after it. 395676e25abSEd Maste */ 396676e25abSEd Maste dl = lma - s->lma; 397676e25abSEd Maste for (i = 0; i < s->seg->nsec; i++) 398676e25abSEd Maste if (s->seg->v_sec[i] == s) 399676e25abSEd Maste break; 400676e25abSEd Maste if (i >= s->seg->nsec) 401676e25abSEd Maste errx(EXIT_FAILURE, "Internal: section `%s' not" 402676e25abSEd Maste " found in its containing segement", 403676e25abSEd Maste s->name); 404676e25abSEd Maste for (; i < s->seg->nsec; i++) { 405676e25abSEd Maste s0 = s->seg->v_sec[i]; 406676e25abSEd Maste s0->lma += dl; 407676e25abSEd Maste #ifdef DEBUG 408676e25abSEd Maste printf("section %s LMA set to %#jx\n", 409676e25abSEd Maste s0->name, (uintmax_t) s0->lma); 410676e25abSEd Maste #endif 411676e25abSEd Maste } 412676e25abSEd Maste } 413676e25abSEd Maste } 414a85fe12eSEd Maste 415a85fe12eSEd Maste /* 416a85fe12eSEd Maste * Issue a warning if there are VMA/LMA adjust requests for 417a85fe12eSEd Maste * some nonexistent sections. 418a85fe12eSEd Maste */ 419a85fe12eSEd Maste if ((ecp->flags & NO_CHANGE_WARN) == 0) { 420a85fe12eSEd Maste STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { 421a85fe12eSEd Maste if (!sac->setvma && !sac->setlma && 422a85fe12eSEd Maste !sac->vma_adjust && !sac->lma_adjust) 423a85fe12eSEd Maste continue; 424a85fe12eSEd Maste found = 0; 425a85fe12eSEd Maste TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 426a85fe12eSEd Maste if (s->pseudo || s->name == NULL) 427a85fe12eSEd Maste continue; 428a85fe12eSEd Maste if (!strcmp(s->name, sac->name)) { 429a85fe12eSEd Maste found = 1; 430a85fe12eSEd Maste break; 431a85fe12eSEd Maste } 432a85fe12eSEd Maste } 433a85fe12eSEd Maste if (!found) 434a85fe12eSEd Maste warnx("cannot find section `%s'", sac->name); 435a85fe12eSEd Maste } 436a85fe12eSEd Maste } 437a85fe12eSEd Maste } 438a85fe12eSEd Maste 439a85fe12eSEd Maste static void 440a85fe12eSEd Maste insert_to_inseg_list(struct segment *seg, struct section *sec) 441a85fe12eSEd Maste { 442a85fe12eSEd Maste struct section *s; 443a85fe12eSEd Maste int i; 444a85fe12eSEd Maste 445a85fe12eSEd Maste seg->nsec++; 446a85fe12eSEd Maste seg->v_sec = realloc(seg->v_sec, seg->nsec * sizeof(*seg->v_sec)); 447a85fe12eSEd Maste if (seg->v_sec == NULL) 448a85fe12eSEd Maste err(EXIT_FAILURE, "realloc failed"); 449a85fe12eSEd Maste 450a85fe12eSEd Maste /* 451a85fe12eSEd Maste * Sort the section in order of offset. 452a85fe12eSEd Maste */ 453a85fe12eSEd Maste 454a85fe12eSEd Maste for (i = seg->nsec - 1; i > 0; i--) { 455a85fe12eSEd Maste s = seg->v_sec[i - 1]; 456a85fe12eSEd Maste if (sec->off >= s->off) { 457a85fe12eSEd Maste seg->v_sec[i] = sec; 458a85fe12eSEd Maste break; 459a85fe12eSEd Maste } else 460a85fe12eSEd Maste seg->v_sec[i] = s; 461a85fe12eSEd Maste } 462a85fe12eSEd Maste if (i == 0) 463a85fe12eSEd Maste seg->v_sec[0] = sec; 464a85fe12eSEd Maste } 465a85fe12eSEd Maste 466a85fe12eSEd Maste void 467a85fe12eSEd Maste setup_phdr(struct elfcopy *ecp) 468a85fe12eSEd Maste { 469a85fe12eSEd Maste struct segment *seg; 470a85fe12eSEd Maste GElf_Phdr iphdr; 471*b6b6f9ccSEd Maste size_t iphnum, i; 472a85fe12eSEd Maste 473a85fe12eSEd Maste if (elf_getphnum(ecp->ein, &iphnum) == 0) 474a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_getphnum failed: %s", 475a85fe12eSEd Maste elf_errmsg(-1)); 476a85fe12eSEd Maste 477a85fe12eSEd Maste ecp->ophnum = ecp->iphnum = iphnum; 478a85fe12eSEd Maste if (iphnum == 0) 479a85fe12eSEd Maste return; 480a85fe12eSEd Maste 481a85fe12eSEd Maste /* If --only-keep-debug is specified, discard all program headers. */ 482a85fe12eSEd Maste if (ecp->strip == STRIP_NONDEBUG) { 483a85fe12eSEd Maste ecp->ophnum = 0; 484a85fe12eSEd Maste return; 485a85fe12eSEd Maste } 486a85fe12eSEd Maste 487*b6b6f9ccSEd Maste for (i = 0; i < iphnum; i++) { 488a85fe12eSEd Maste if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr) 489a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getphdr failed: %s", 490a85fe12eSEd Maste elf_errmsg(-1)); 491a85fe12eSEd Maste if ((seg = calloc(1, sizeof(*seg))) == NULL) 492a85fe12eSEd Maste err(EXIT_FAILURE, "calloc failed"); 493676e25abSEd Maste seg->vaddr = iphdr.p_vaddr; 494676e25abSEd Maste seg->paddr = iphdr.p_paddr; 495a85fe12eSEd Maste seg->off = iphdr.p_offset; 496a85fe12eSEd Maste seg->fsz = iphdr.p_filesz; 497a85fe12eSEd Maste seg->msz = iphdr.p_memsz; 498a85fe12eSEd Maste seg->type = iphdr.p_type; 499a85fe12eSEd Maste STAILQ_INSERT_TAIL(&ecp->v_seg, seg, seg_list); 500a85fe12eSEd Maste } 501a85fe12eSEd Maste } 502a85fe12eSEd Maste 503a85fe12eSEd Maste void 504a85fe12eSEd Maste copy_phdr(struct elfcopy *ecp) 505a85fe12eSEd Maste { 506a85fe12eSEd Maste struct segment *seg; 507a85fe12eSEd Maste struct section *s; 508a85fe12eSEd Maste GElf_Phdr iphdr, ophdr; 509a85fe12eSEd Maste int i; 510a85fe12eSEd Maste 511a85fe12eSEd Maste STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { 512a85fe12eSEd Maste if (seg->type == PT_PHDR) { 513a85fe12eSEd Maste if (!TAILQ_EMPTY(&ecp->v_sec)) { 514a85fe12eSEd Maste s = TAILQ_FIRST(&ecp->v_sec); 515676e25abSEd Maste if (s->pseudo) { 516676e25abSEd Maste seg->vaddr = s->vma + 517a85fe12eSEd Maste gelf_fsize(ecp->eout, ELF_T_EHDR, 518a85fe12eSEd Maste 1, EV_CURRENT); 519676e25abSEd Maste seg->paddr = s->lma + 520676e25abSEd Maste gelf_fsize(ecp->eout, ELF_T_EHDR, 521676e25abSEd Maste 1, EV_CURRENT); 522676e25abSEd Maste } 523a85fe12eSEd Maste } 524a85fe12eSEd Maste seg->fsz = seg->msz = gelf_fsize(ecp->eout, ELF_T_PHDR, 525a85fe12eSEd Maste ecp->ophnum, EV_CURRENT); 526a85fe12eSEd Maste continue; 527a85fe12eSEd Maste } 528a85fe12eSEd Maste 529676e25abSEd Maste if (seg->nsec > 0) { 530676e25abSEd Maste s = seg->v_sec[0]; 531676e25abSEd Maste seg->vaddr = s->vma; 532676e25abSEd Maste seg->paddr = s->lma; 533676e25abSEd Maste } 534676e25abSEd Maste 535a85fe12eSEd Maste seg->fsz = seg->msz = 0; 536a85fe12eSEd Maste for (i = 0; i < seg->nsec; i++) { 537a85fe12eSEd Maste s = seg->v_sec[i]; 538676e25abSEd Maste seg->msz = s->vma + s->sz - seg->vaddr; 539a85fe12eSEd Maste if (s->type != SHT_NOBITS) 540b00fe64fSEd Maste seg->fsz = s->off + s->sz - seg->off; 541a85fe12eSEd Maste } 542a85fe12eSEd Maste } 543a85fe12eSEd Maste 544a85fe12eSEd Maste /* 545a85fe12eSEd Maste * Allocate space for program headers, note that libelf keep 546a85fe12eSEd Maste * track of the number in internal variable, and a call to 547a85fe12eSEd Maste * elf_update is needed to update e_phnum of ehdr. 548a85fe12eSEd Maste */ 549a85fe12eSEd Maste if (gelf_newphdr(ecp->eout, ecp->ophnum) == NULL) 550a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_newphdr() failed: %s", 551a85fe12eSEd Maste elf_errmsg(-1)); 552a85fe12eSEd Maste 553a85fe12eSEd Maste /* 554a85fe12eSEd Maste * This elf_update() call is to update the e_phnum field in 555a85fe12eSEd Maste * ehdr. It's necessary because later we will call gelf_getphdr(), 556a85fe12eSEd Maste * which does sanity check by comparing ndx argument with e_phnum. 557a85fe12eSEd Maste */ 558a85fe12eSEd Maste if (elf_update(ecp->eout, ELF_C_NULL) < 0) 559a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1)); 560a85fe12eSEd Maste 561a85fe12eSEd Maste /* 562a85fe12eSEd Maste * iphnum == ophnum, since we don't remove program headers even if 563a85fe12eSEd Maste * they no longer contain sections. 564a85fe12eSEd Maste */ 565a85fe12eSEd Maste i = 0; 566a85fe12eSEd Maste STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) { 567a85fe12eSEd Maste if (i >= ecp->iphnum) 568a85fe12eSEd Maste break; 569a85fe12eSEd Maste if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr) 570a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getphdr failed: %s", 571a85fe12eSEd Maste elf_errmsg(-1)); 572a85fe12eSEd Maste if (gelf_getphdr(ecp->eout, i, &ophdr) != &ophdr) 573a85fe12eSEd Maste errx(EXIT_FAILURE, "gelf_getphdr failed: %s", 574a85fe12eSEd Maste elf_errmsg(-1)); 575a85fe12eSEd Maste 576a85fe12eSEd Maste ophdr.p_type = iphdr.p_type; 577676e25abSEd Maste ophdr.p_vaddr = seg->vaddr; 578676e25abSEd Maste ophdr.p_paddr = seg->paddr; 579a85fe12eSEd Maste ophdr.p_flags = iphdr.p_flags; 580a85fe12eSEd Maste ophdr.p_align = iphdr.p_align; 581a85fe12eSEd Maste ophdr.p_offset = seg->off; 582a85fe12eSEd Maste ophdr.p_filesz = seg->fsz; 583a85fe12eSEd Maste ophdr.p_memsz = seg->msz; 584a85fe12eSEd Maste if (!gelf_update_phdr(ecp->eout, i, &ophdr)) 585839529caSEd Maste errx(EXIT_FAILURE, "gelf_update_phdr failed: %s", 586a85fe12eSEd Maste elf_errmsg(-1)); 587a85fe12eSEd Maste 588a85fe12eSEd Maste i++; 589a85fe12eSEd Maste } 590a85fe12eSEd Maste } 591