1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file. 4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* 6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Copyright (C) 2012 The Android Open Source Project 7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * All rights reserved. 8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without 10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * modification, are permitted provided that the following conditions 11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * are met: 12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * * Redistributions of source code must retain the above copyright 13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * notice, this list of conditions and the following disclaimer. 14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * * Redistributions in binary form must reproduce the above copyright 15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * notice, this list of conditions and the following disclaimer in 16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * the documentation and/or other materials provided with the 17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * distribution. 18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * SUCH DAMAGE. 31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "linker_phdr.h" 34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <errno.h> 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <fcntl.h> 37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <sys/mman.h> 38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <unistd.h> 39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define PAGE_START(x) ((x) & PAGE_MASK) 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK) 42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE - 1)) 43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Missing exec_elf.h definitions. 45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifndef PT_GNU_RELRO 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define PT_GNU_RELRO 0x6474e552 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) TECHNICAL NOTE ON ELF LOADING. 51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) An ELF file's program header table contains one or more PT_LOAD 53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) segments, which corresponds to portions of the file that need to 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) be mapped into the process' address space. 55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Each loadable segment has the following important properties: 57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) p_offset -> segment file offset 59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) p_filesz -> segment file size 60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) p_memsz -> segment memory size (always >= p_filesz) 61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) p_vaddr -> segment's virtual address 62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) p_flags -> segment flags (e.g. readable, writable, executable) 63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) We will ignore the p_paddr and p_align fields of ELF::Phdr for now. 65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) The loadable segments can be seen as a list of [p_vaddr ... p_vaddr+p_memsz) 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ranges of virtual addresses. A few rules apply: 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) - the virtual address ranges should not overlap. 70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) - if a segment's p_filesz is smaller than its p_memsz, the extra bytes 72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) between them should always be initialized to 0. 73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) - ranges do not necessarily start or end at page boundaries. Two distinct 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) segments can have their start and end on the same page. In this case, the 76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) page inherits the mapping flags of the latter segment. 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Finally, the real load addrs of each segment is not p_vaddr. Instead the 79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) loader decides where to load the first segment, then will load all others 80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relative to the first one to respect the initial range layout. 81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) For example, consider the following list: 83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) [ offset:0, filesz:0x4000, memsz:0x4000, vaddr:0x30000 ], 85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) [ offset:0x4000, filesz:0x2000, memsz:0x8000, vaddr:0x40000 ], 86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) This corresponds to two segments that cover these virtual address ranges: 88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 0x30000...0x34000 90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 0x40000...0x48000 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) If the loader decides to load the first segment at address 0xa0000000 93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) then the segments' load address ranges will be: 94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 0xa0030000...0xa0034000 96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 0xa0040000...0xa0048000 97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) In other words, all segments must be loaded at an address that has the same 99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) constant offset from their p_vaddr value. This offset is computed as the 100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) difference between the first segment's load address, and its p_vaddr value. 101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) However, in practice, segments do _not_ start at page boundaries. Since we 103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) can only memory-map at page boundaries, this means that the bias is 104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) computed as: 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) load_bias = phdr0_load_address - PAGE_START(phdr0->p_vaddr) 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (NOTE: The value must be used as a 32-bit unsigned integer, to deal with 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) possible wrap around UINT32_MAX for possible large p_vaddr values). 110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) And that the phdr0_load_address must start at a page boundary, with 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) the segment's real content starting at: 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) phdr0_load_address + PAGE_OFFSET(phdr0->p_vaddr) 115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Note that ELF requires the following condition to make the mmap()-ing work: 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PAGE_OFFSET(phdr0->p_vaddr) == PAGE_OFFSET(phdr0->p_offset) 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) The load_bias must be added to any p_vaddr value read from the ELF file to 121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) determine the corresponding memory address. 122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) **/ 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define MAYBE_MAP_FLAG(x, from, to) (((x) & (from)) ? (to) : 0) 126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define PFLAGS_TO_PROT(x) \ 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \ 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \ 129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE)) 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* Returns the size of the extent of all the possibly non-contiguous 132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * loadable segments in an ELF program header table. This corresponds 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * to the page-aligned size in bytes that needs to be reserved in the 134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * process' address space. If there are no loadable segments, 0 is 135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * returned. 136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * If out_min_vaddr or out_max_vaddr are non-NULL, they will be 138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * set to the minimum and maximum addresses of pages to be reserved, 139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * or 0 if there is nothing to load. 140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)size_t phdr_table_get_load_size(const ELF::Phdr* phdr_table, 142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t phdr_count, 143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr* out_min_vaddr, 144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr* out_max_vaddr) { 145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr min_vaddr = ~static_cast<ELF::Addr>(0); 146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr max_vaddr = 0x00000000U; 147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool found_pt_load = false; 149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (size_t i = 0; i < phdr_count; ++i) { 150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Phdr* phdr = &phdr_table[i]; 151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (phdr->p_type != PT_LOAD) { 153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) found_pt_load = true; 156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (phdr->p_vaddr < min_vaddr) { 158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) min_vaddr = phdr->p_vaddr; 159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) { 162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) max_vaddr = phdr->p_vaddr + phdr->p_memsz; 163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!found_pt_load) { 166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) min_vaddr = 0x00000000U; 167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) min_vaddr = PAGE_START(min_vaddr); 170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) max_vaddr = PAGE_END(max_vaddr); 171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (out_min_vaddr != NULL) { 173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *out_min_vaddr = min_vaddr; 174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (out_max_vaddr != NULL) { 176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *out_max_vaddr = max_vaddr; 177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return max_vaddr - min_vaddr; 179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* Used internally. Used to set the protection bits of all loaded segments 182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * with optional extra flags (i.e. really PROT_WRITE). Used by 183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_table_protect_segments and phdr_table_unprotect_segments. 184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)static int _phdr_table_set_load_prot(const ELF::Phdr* phdr_table, 186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int phdr_count, 187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr load_bias, 188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int extra_prot_flags) { 189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Phdr* phdr = phdr_table; 190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Phdr* phdr_limit = phdr + phdr_count; 191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (; phdr < phdr_limit; phdr++) { 193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0) 194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias; 197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr seg_page_end = 198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias; 199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int ret = mprotect((void*)seg_page_start, 201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) seg_page_end - seg_page_start, 202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags); 203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (ret < 0) { 204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return -1; 205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return 0; 208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* Restore the original protection modes for all loadable segments. 211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * You should only call this after phdr_table_unprotect_segments and 212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * applying all relocations. 213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Input: 215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_table -> program header table 216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_count -> number of entries in tables 217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * load_bias -> load bias 218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Return: 219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 0 on error, -1 on failure (error code in errno). 220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)int phdr_table_protect_segments(const ELF::Phdr* phdr_table, 222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int phdr_count, 223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr load_bias) { 224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return _phdr_table_set_load_prot(phdr_table, phdr_count, load_bias, 0); 225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* Change the protection of all loaded segments in memory to writable. 228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * This is useful before performing relocations. Once completed, you 229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * will have to call phdr_table_protect_segments to restore the original 230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * protection flags on all segments. 231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Note that some writable segments can also have their content turned 233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * to read-only by calling phdr_table_protect_gnu_relro. This is no 234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * performed here. 235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Input: 237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_table -> program header table 238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_count -> number of entries in tables 239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * load_bias -> load bias 240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Return: 241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 0 on error, -1 on failure (error code in errno). 242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)int phdr_table_unprotect_segments(const ELF::Phdr* phdr_table, 244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int phdr_count, 245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr load_bias) { 246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return _phdr_table_set_load_prot( 247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) phdr_table, phdr_count, load_bias, PROT_WRITE); 248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* Return the extend of the GNU RELRO segment in a program header. 251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * On success, return 0 and sets |*relro_start| and |*relro_end| 252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * to the page-aligned extents of the RELRO section. 253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * On failure, return -1. 254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * NOTE: This assumes there is a single PT_GNU_RELRO segment in the 256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * program header, i.e. it will return the extents of the first entry. 257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)int phdr_table_get_relro_info(const ELF::Phdr* phdr_table, 259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int phdr_count, 260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr load_bias, 261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr* relro_start, 262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr* relro_size) { 263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Phdr* phdr; 264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Phdr* phdr_limit = phdr_table + phdr_count; 265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (phdr = phdr_table; phdr < phdr_limit; ++phdr) { 267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (phdr->p_type != PT_GNU_RELRO) 268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) /* Tricky: what happens when the relro segment does not start 271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * or end at page boundaries?. We're going to be over-protective 272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * here and put every page touched by the segment as read-only. 273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * This seems to match Ian Lance Taylor's description of the 275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * feature at http://www.airs.com/blog/archives/189. 276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Extract: 278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Note that the current dynamic linker code will only work 279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * correctly if the PT_GNU_RELRO segment starts on a page 280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * boundary. This is because the dynamic linker rounds the 281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * p_vaddr field down to the previous page boundary. If 282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * there is anything on the page which should not be read-only, 283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * the program is likely to fail at runtime. So in effect the 284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * linker must only emit a PT_GNU_RELRO segment if it ensures 285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * that it starts on a page boundary. 286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *relro_start = PAGE_START(phdr->p_vaddr) + load_bias; 288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *relro_size = 289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias - *relro_start; 290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return 0; 291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return -1; 294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* Apply GNU relro protection if specified by the program header. This will 297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * turn some of the pages of a writable PT_LOAD segment to read-only, as 298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * specified by one or more PT_GNU_RELRO segments. This must be always 299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * performed after relocations. 300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * The areas typically covered are .got and .data.rel.ro, these are 302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * read-only from the program's POV, but contain absolute addresses 303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * that need to be relocated before use. 304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Input: 306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_table -> program header table 307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_count -> number of entries in tables 308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * load_bias -> load bias 309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Return: 310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 0 on error, -1 on failure (error code in errno). 311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)int phdr_table_protect_gnu_relro(const ELF::Phdr* phdr_table, 313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int phdr_count, 314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr load_bias) { 315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr relro_start, relro_size; 316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (phdr_table_get_relro_info( 318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) phdr_table, phdr_count, load_bias, &relro_start, &relro_size) < 0) { 319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return -1; 320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return mprotect((void*)relro_start, relro_size, PROT_READ); 323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __arm__ 326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifndef PT_ARM_EXIDX 328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */ 329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif 330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* Return the address and size of the .ARM.exidx section in memory, 332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * if present. 333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Input: 335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_table -> program header table 336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_count -> number of entries in tables 337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * load_bias -> load bias 338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Output: 339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * arm_exidx -> address of table in memory (NULL on failure). 340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * arm_exidx_count -> number of items in table (0 on failure). 341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Return: 342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 0 on error, -1 on failure (_no_ error code in errno) 343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)int phdr_table_get_arm_exidx(const ELF::Phdr* phdr_table, 345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int phdr_count, 346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr load_bias, 347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr** arm_exidx, 348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) unsigned* arm_exidx_count) { 349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Phdr* phdr = phdr_table; 350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Phdr* phdr_limit = phdr + phdr_count; 351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (phdr = phdr_table; phdr < phdr_limit; phdr++) { 353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (phdr->p_type != PT_ARM_EXIDX) 354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *arm_exidx = (ELF::Addr*)(load_bias + phdr->p_vaddr); 357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *arm_exidx_count = (unsigned)(phdr->p_memsz / 8); 358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return 0; 359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *arm_exidx = NULL; 361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *arm_exidx_count = 0; 362f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return -1; 363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif // __arm__ 365f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 366f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/* Return the address and size of the ELF file's .dynamic section in memory, 367f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * or NULL if missing. 368f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 369f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Input: 370f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_table -> program header table 371f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * phdr_count -> number of entries in tables 372f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * load_bias -> load bias 373f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Output: 374f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * dynamic -> address of table in memory (NULL on failure). 375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * dynamic_count -> number of items in table (0 on failure). 376f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * dynamic_flags -> protection flags for section (unset on failure) 377f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Return: 378f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * void 379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 380f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void phdr_table_get_dynamic_section(const ELF::Phdr* phdr_table, 381f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int phdr_count, 382f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Addr load_bias, 383f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Dyn** dynamic, 384f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t* dynamic_count, 385f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ELF::Word* dynamic_flags) { 386f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Phdr* phdr = phdr_table; 387f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ELF::Phdr* phdr_limit = phdr + phdr_count; 388f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 389f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (phdr = phdr_table; phdr < phdr_limit; phdr++) { 390f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (phdr->p_type != PT_DYNAMIC) { 391f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 392f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 393f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 394f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *dynamic = reinterpret_cast<const ELF::Dyn*>(load_bias + phdr->p_vaddr); 395f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (dynamic_count) { 396f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *dynamic_count = (unsigned)(phdr->p_memsz / sizeof(ELF::Dyn)); 397f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 398f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (dynamic_flags) { 399f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *dynamic_flags = phdr->p_flags; 400f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 401f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 402f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 403f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *dynamic = NULL; 404f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (dynamic_count) { 405f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *dynamic_count = 0; 406f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 407f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 408