crazy_linker_elf_relro.cpp revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// found in the LICENSE file. 493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "crazy_linker_elf_relro.h" 693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <errno.h> 893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <limits.h> 993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include <stdlib.h> 1093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 1193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "crazy_linker_elf_relocations.h" 1293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "crazy_linker_elf_view.h" 1393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "crazy_linker_memory_mapping.h" 1493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "crazy_linker_util.h" 1593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 1693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)namespace crazy { 1793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 1893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)namespace { 1993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 2093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)inline bool PageEquals(const char* p1, const char* p2) { 2193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return ::memcmp(p1, p2, PAGE_SIZE) == 0; 2293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)} 2393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 2493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// Swap pages between |addr| and |addr + size| with the bytes 2593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// from the ashmem region identified by |fd|, starting from 2693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// a given |offset|. On failure return false and set |error| message. 2793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SwapPagesFromFd(void* addr, 2893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t size, 2993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) int fd, 3093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t offset, 3193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) Error* error) { 3293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Unmap current pages. 3393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (::munmap(addr, size) < 0) { 3493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) error->Format("%s: Could not unmap %p-%p: %s", 3593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) __FUNCTION__, 3693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) addr, 3793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) (char*)addr + size, 3893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) strerror(errno)); 3993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return false; 4093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } 4193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 4293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Remap the fd pages at the same location now. 4393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) void* new_map = ::mmap(addr, 4493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size, 4593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) PROT_READ, 4693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) MAP_FIXED | MAP_SHARED, 4793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) fd, 4893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) static_cast<off_t>(offset)); 4993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (new_map == MAP_FAILED) { 5093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) char* p = reinterpret_cast<char*>(addr); 5193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) error->Format("%s: Could not map %p-%p: %s", 5293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) __FUNCTION__, 5393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) p, 5493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) p + size, 5593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) strerror(errno)); 5693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return false; 5793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } 5893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 5993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// TODO(digit): Is this necessary? 6093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#ifdef __arm__ 6193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) __clear_cache(addr, (char*)addr + size); 6293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#endif 6393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 6493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Done. 6593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return true; 6693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)} 6793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 6893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)} // namespace 6993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 7093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SharedRelro::Allocate(size_t relro_size, 7193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) const char* library_name, 7293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) Error* error) { 7393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Allocate a new ashmem region. 7493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) String name("RELRO:"); 7593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) name += library_name; 7693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (!ashmem_.Allocate(relro_size, name.c_str())) { 7793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) error->Format("Could not allocate RELRO ashmem region for %s: %s", 7893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) library_name, 7993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) strerror(errno)); 8093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return false; 8193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } 8293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 8393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) start_ = 0; 8493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_ = relro_size; 8593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return true; 8693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)} 8793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 8893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SharedRelro::CopyFrom(size_t relro_start, 8993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t relro_size, 9093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) Error* error) { 9193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Map it in the process. 9293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) ScopedMemoryMapping map; 9393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (!map.Allocate(NULL, relro_size, MemoryMapping::CAN_WRITE, ashmem_.fd())) { 9493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) error->Format("Could not allocate RELRO mapping: %s", strerror(errno)); 9593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return false; 9693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } 9793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 9893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Copy process' RELRO into it. 9993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) ::memcpy(map.Get(), reinterpret_cast<void*>(relro_start), relro_size); 10093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 10193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Unmap it. 10293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) map.Deallocate(); 10393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 10493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Everything's good. 10593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) start_ = relro_start; 10693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_ = relro_size; 10793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return true; 10893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)} 10993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 11093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SharedRelro::CopyFromRelocated(const ElfView* view, 11193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t load_address, 11293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t relro_start, 11393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t relro_size, 11493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) Error* error) { 11593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Offset of RELRO section in current library. 11693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t relro_offset = relro_start - view->load_address(); 11793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 11893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) ElfRelocations relocations; 11993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (!relocations.Init(view, error)) 12093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return false; 12193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 12293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Map the region in memory (any address). 12393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) ScopedMemoryMapping map; 12493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (!map.Allocate( 12593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) NULL, relro_size, MemoryMapping::CAN_READ_WRITE, ashmem_.fd())) { 12693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) error->Format("Could not allocate RELRO mapping for: %s", strerror(errno)); 12793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return false; 12893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } 12993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 13093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Copy and relocate. 13193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) relocations.CopyAndRelocate(relro_start, 13293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) reinterpret_cast<size_t>(map.Get()), 13393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) load_address + relro_offset, 13493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) relro_size); 13593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Unmap it. 13693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) map.Deallocate(); 13793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) start_ = load_address + relro_offset; 13893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_ = relro_size; 13993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return true; 14093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)} 14193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 14293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SharedRelro::ForceReadOnly(Error* error) { 14393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Ensure the ashmem region content isn't writable anymore. 14493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (!ashmem_.SetProtectionFlags(PROT_READ)) { 14593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) error->Format("Could not make RELRO ashmem region read-only: %s", 14693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) strerror(errno)); 14793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return false; 14893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } 14993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return true; 15093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)} 15193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 15293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SharedRelro::InitFrom(size_t relro_start, 15393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t relro_size, 15493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) int ashmem_fd, 15593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) Error* error) { 15693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Create temporary mapping of the ashmem region. 15793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) ScopedMemoryMapping fd_map; 15893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 15993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) LOG("%s: Entering addr=%p size=%p fd=%d\n", 16093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) __FUNCTION__, 16193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) (void*)relro_start, 16293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) (void*)relro_size, 16393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) ashmem_fd); 16493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 16593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Sanity check: Ashmem file descriptor must be read-only. 16693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (!AshmemRegion::CheckFileDescriptorIsReadOnly(ashmem_fd)) { 16793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) error->Format("Ashmem file descriptor is not read-only: %s\n", 16893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) strerror(errno)); 16993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return false; 17093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } 17193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 17293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (!fd_map.Allocate(NULL, relro_size, MemoryMapping::CAN_READ, ashmem_fd)) { 17393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) error->Format("Cannot map RELRO ashmem region as read-only: %s\n", 17493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) strerror(errno)); 17593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return false; 17693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } 17793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 17893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) LOG("%s: mapping allocated at %p\n", __FUNCTION__, fd_map.Get()); 17993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 18093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) char* cur_page = reinterpret_cast<char*>(relro_start); 18193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) char* fd_page = static_cast<char*>(fd_map.Get()); 18293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t p = 0; 18393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t size = relro_size; 18493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t similar_size = 0; 18593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 18693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) do { 18793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Skip over dissimilar pages. 18893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) while (p < size && !PageEquals(cur_page + p, fd_page + p)) { 18993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) p += PAGE_SIZE; 19093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } 19193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 19293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Count similar pages. 19393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) size_t p2 = p; 19493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) while (p2 < size && PageEquals(cur_page + p2, fd_page + p2)) { 19593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) p2 += PAGE_SIZE; 19693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) } 19793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) 19893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (p2 > p) { 19993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) // Swap pages between |pos| and |pos2|. 20093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) LOG("%s: Swap pages at %p-%p\n", 20193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) __FUNCTION__, 20293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) cur_page + p, 20393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) cur_page + p2); 20493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (!SwapPagesFromFd(cur_page + p, p2 - p, ashmem_fd, p, error)) 20593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) return false; 206 207 similar_size += (p2 - p); 208 } 209 210 p = p2; 211 } while (p < size); 212 213 LOG("%s: Swapped %d pages over %d (%d %%, %d KB not shared)\n", 214 __FUNCTION__, 215 similar_size / PAGE_SIZE, 216 size / PAGE_SIZE, 217 similar_size * 100 / size, 218 (size - similar_size) / 4096); 219 220 if (similar_size == 0) 221 return false; 222 223 start_ = relro_start; 224 size_ = relro_size; 225 return true; 226} 227 228} // namespace crazy 229