1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "crazy_linker_elf_view.h"
9 #include "crazy_linker_debug.h"
10 #include "crazy_linker_error.h"
11 #include "linker_phdr.h"
15 bool ElfView::InitUnmapped(ELF::Addr load_address,
16 const ELF::Phdr* phdr,
19 // Compute load size and bias.
20 ELF::Addr min_vaddr = 0;
21 load_size_ = phdr_table_get_load_size(phdr, phdr_count, &min_vaddr, NULL);
22 if (load_size_ == 0) {
23 *error = "Invalid program header table";
26 load_address_ = (load_address ? load_address : min_vaddr);
27 load_bias_ = load_address - min_vaddr;
29 // Extract the dynamic table information.
30 phdr_table_get_dynamic_section(phdr,
37 *error = "No PT_DYNAMIC section!";
41 // Compute the program header table address relative to load_address.
42 // This is different from |phdr|..|phdr + phdr_count| which can actually
43 // be at a different location.
44 const ELF::Phdr* phdr0 = NULL;
46 // First, if there is a PT_PHDR, use it directly.
47 for (size_t n = 0; n < phdr_count; ++n) {
48 const ELF::Phdr* entry = &phdr[n];
49 if (entry->p_type == PT_PHDR) {
55 // Otherwise, check the first loadable segment. If its file offset
56 // is 0, it starts with the ELF header, and we can trivially find the
57 // loaded program header from it.
59 for (size_t n = 0; n < phdr_count; ++n) {
60 const ELF::Phdr* entry = &phdr[n];
61 if (entry->p_type == PT_LOAD) {
62 if (entry->p_offset == 0) {
63 ELF::Addr elf_addr = load_bias_ + entry->p_vaddr;
64 const ELF::Ehdr* ehdr = reinterpret_cast<const ELF::Ehdr*>(elf_addr);
65 ELF::Addr offset = ehdr->e_phoff;
66 phdr0 = reinterpret_cast<const ELF::Phdr*>(elf_addr + offset);
73 // Check that the program header table is indeed in a loadable segment,
74 // this helps catching malformed ELF binaries.
76 ELF::Addr phdr0_addr = reinterpret_cast<ELF::Addr>(phdr0);
77 ELF::Addr phdr0_limit = phdr0_addr + sizeof(ELF::Phdr) * phdr_count;
79 for (size_t n = 0; n < phdr_count; ++n) {
80 size_t seg_start = load_bias_ + phdr[n].p_vaddr;
81 size_t seg_end = seg_start + phdr[n].p_filesz;
83 if (seg_start <= phdr0_addr && phdr0_limit <= seg_end) {
94 *error = "Malformed ELF binary";
99 phdr_count_ = phdr_count;
101 LOG("%s: New ELF view [load_address:%p, load_size:%p, load_bias:%p, phdr:%p, "
102 "phdr_count:%d, dynamic:%p, dynamic_count:%d, dynamic_flags:%d\n",
115 bool ElfView::ProtectRelroSection(Error* error) {
116 LOG("%s: Enabling GNU RELRO protection\n", __FUNCTION__);
118 if (phdr_table_protect_gnu_relro(phdr_, phdr_count_, load_bias_) < 0) {
119 error->Format("Can't enable GNU RELRO protection: %s", strerror(errno));