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