148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Copyright (c) 2013 The Chromium Authors. All rights reserved.
248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Use of this source code is governed by a BSD-style license that can be
348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// found in the LICENSE file.
448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#ifndef CRAZY_LINKER_ELF_LOADER_H
648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#define CRAZY_LINKER_ELF_LOADER_H
748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_error.h"
948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "crazy_linker_system.h"  // For ScopedFileDescriptor
1048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#include "elf_traits.h"
1148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
1248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnernamespace crazy {
1348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
1448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Helper class used to load an ELF binary in memory.
1548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner//
1648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// Note that this doesn't not perform any relocation, the purpose
1748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// of this class is strictly to map all loadable segments from the
1848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner// file to their correct location.
1948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner//
2048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turnerclass ElfLoader {
2148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner public:
2248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ElfLoader();
2348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ~ElfLoader();
2448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
2548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Try to load a library at a given address. On failure, this will
2648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // update the linker error message and returns false.
2748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  //
2848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // |lib_path| is the full library path, and |wanted_address| should
2948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // be the desired load address, or 0 to enable randomization.
3048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  //
3148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // |file_offset| is an offset in the file where the ELF header will
3248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // be looked for.
3348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  //
3448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // |wanted_address| is the wanted load address (of the first loadable
3548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // segment), or 0 to enable randomization.
3648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  //
3748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // On success, the library's loadable segments will be mapped in
3848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // memory with their original protection. However, no further processing
3948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // will be performed.
4048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  //
4148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // On failure, returns false and assign an error message to |error|.
4248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  bool LoadAt(const char* lib_path,
4348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner              off_t file_offset,
4448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner              uintptr_t wanted_address,
4548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner              Error* error);
4648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
4748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Only call the following functions after a succesfull LoadAt() call.
4848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
4948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  size_t phdr_count() { return phdr_num_; }
5048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Addr load_start() { return reinterpret_cast<ELF::Addr>(load_start_); }
5148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Addr load_size() { return load_size_; }
5248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Addr load_bias() { return load_bias_; }
5348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  const ELF::Phdr* loaded_phdr() { return loaded_phdr_; }
5448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
5548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner private:
5648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  FileDescriptor fd_;
5748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  const char* path_;
5848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
5948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Ehdr header_;
6048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  size_t phdr_num_;
6148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
6248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  void* phdr_mmap_;  // temporary copy of the program header.
6348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Phdr* phdr_table_;
6448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Addr phdr_size_;  // and its size.
6548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
6648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  off_t file_offset_;
6748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  void* wanted_load_address_;
6848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  void* load_start_;     // First page of reserved address space.
6948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Addr load_size_;  // Size in bytes of reserved address space.
7048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  ELF::Addr load_bias_;  // load_bias, add this value to all "vaddr"
7148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                         // values in the library to get the corresponding
7248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner                         // memory address.
7348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
7448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  const ELF::Phdr* loaded_phdr_;  // points to the loaded program header.
7548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
7648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  // Individual steps used by ::LoadAt()
7748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  bool ReadElfHeader(Error* error);
7848cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  bool ReadProgramHeader(Error* error);
7948cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  bool ReserveAddressSpace(Error* error);
8048cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  bool LoadSegments(Error* error);
8148cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  bool FindPhdr(Error* error);
8248cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner  bool CheckPhdr(ELF::Addr, Error* error);
8348cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner};
8448cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
8548cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner}  // namespace crazy
8648cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner
8748cdce8c044f6e7d11aa2b5eb97635c922e0bc58David 'Digit' Turner#endif  // CRAZY_LINKER_ELF_LOADER_H
88