1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file. 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#ifndef COURGETTE_DISASSEMBLER_ELF_32_H_ 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#define COURGETTE_DISASSEMBLER_ELF_32_H_ 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/basictypes.h" 9a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/memory/scoped_vector.h" 10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "courgette/assembly_program.h" 11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/disassembler.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/memory_allocator.h" 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/types_elf.h" 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace courgette { 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass AssemblyProgram; 18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// A courgette disassembler for 32-bit ELF files. This class is only a 20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// partial implementation. Subclasses implement the 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// architecture-specific parts of processing 32-bit ELF files. Specifically, 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// RelToRVA processes entries in ELF relocation table, 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// ParseRelocationSection verifies the organization of the ELF 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// relocation table, and ParseRel32RelocsFromSection finds branch 25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// targets by looking for relative jump/call opcodes in the particular 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// architecture's machine code. 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass DisassemblerElf32 : public Disassembler { 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public: 29a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // Different instructions encode the target rva differently. This 30a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // class encapsulates this behavior. public for use in unit tests. 31a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch class TypedRVA { 32a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch public: 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch explicit TypedRVA(RVA rva) : rva_(rva), offset_(static_cast<size_t>(-1)) { 34a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 35a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 36a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch virtual ~TypedRVA() { }; 37a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 38a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch RVA rva() { 39a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return rva_; 40a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 41a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 42a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch RVA relative_target() { 43a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return relative_target_; 44a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 45a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 46a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch void set_relative_target(RVA relative_target) { 47a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch relative_target_ = relative_target; 48a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 49a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 50a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch size_t get_offset() { 51a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return offset_; 52a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 53a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 54a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch void set_offset(size_t offset) { 55a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch offset_ = offset; 56a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 57a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Computes the relative jump's offset from the op in p. 59a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch virtual CheckBool ComputeRelativeTarget(const uint8* op_pointer) = 0; 60a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Emits the courgette instruction corresponding to the RVA type. 62a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) virtual CheckBool EmitInstruction(AssemblyProgram* program, 63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) RVA target_rva) = 0; 64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) virtual uint16 op_size() const = 0; 66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 67a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch static bool IsLessThan(TypedRVA *a, TypedRVA *b) { 68a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return a->rva() < b->rva(); 69a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 70a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 71a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch private: 72a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const RVA rva_; 73a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch RVA relative_target_; 74a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch size_t offset_; 75a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch }; 76a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 77a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch public: 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch explicit DisassemblerElf32(const void* start, size_t length); 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 80a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch virtual ~DisassemblerElf32() { }; 81a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual ExecutableType kind() = 0; 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual e_machine_values ElfEM() = 0; 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Returns 'true' if the buffer appears to point to a valid ELF executable 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // for 32 bit. If ParseHeader() succeeds, other member 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // functions may be called. 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual bool ParseHeader(); 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual bool Disassemble(AssemblyProgram* target); 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Public for unittests only 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::vector<RVA> &Abs32Locations() { return abs32_locations_; } 95a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch ScopedVector<TypedRVA> &Rel32Locations() { return rel32_locations_; } 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch protected: 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32 DiscoverLength(); 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Misc Section Helpers 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Half SectionHeaderCount() const { 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return section_header_table_size_; 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const Elf32_Shdr *SectionHeader(int id) const { 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch assert(id >= 0 && id < SectionHeaderCount()); 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return section_header_table_ + id; 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const uint8 *SectionBody(int id) const { 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return OffsetToPointer(SectionHeader(id)->sh_offset); 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Word SectionBodySize(int id) const { 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return SectionHeader(id)->sh_size; 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Misc Segment Helpers 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Half ProgramSegmentHeaderCount() const { 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return program_header_table_size_; 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const Elf32_Phdr *ProgramSegmentHeader(int id) const { 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch assert(id >= 0 && id < ProgramSegmentHeaderCount()); 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return program_header_table_ + id; 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The virtual memory address at which this program segment will be loaded 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Addr ProgramSegmentMemoryBegin(int id) const { 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return ProgramSegmentHeader(id)->p_vaddr; 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The number of virtual memory bytes for this program segment 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Word ProgramSegmentMemorySize(int id) const { 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return ProgramSegmentHeader(id)->p_memsz; 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Pointer into the source file for this program segment 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Addr ProgramSegmentFileOffset(int id) const { 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return ProgramSegmentHeader(id)->p_offset; 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Number of file bytes for this program segment. Is <= ProgramMemorySize. 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Word ProgramSegmentFileSize(int id) const { 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return ProgramSegmentHeader(id)->p_filesz; 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Misc address space helpers 152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CheckBool IsValidRVA(RVA rva) const WARN_UNUSED_RESULT; 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Convert an ELF relocation struction into an RVA 156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual CheckBool RelToRVA(Elf32_Rel rel, RVA* result) 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const WARN_UNUSED_RESULT = 0; 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Returns kNoOffset if there is no file offset corresponding to 'rva'. 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CheckBool RVAToFileOffset(RVA rva, size_t* result) const WARN_UNUSED_RESULT; 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch RVA FileOffsetToRVA(size_t offset) const WARN_UNUSED_RESULT; 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CheckBool RVAsToOffsets(std::vector<RVA>* rvas /*in*/, 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::vector<size_t>* offsets /*out*/); 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 167a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch CheckBool RVAsToOffsets(ScopedVector<TypedRVA>* rvas /*in and out*/); 168a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Parsing Code used to really implement Disassemble 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CheckBool ParseFile(AssemblyProgram* target) WARN_UNUSED_RESULT; 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual CheckBool ParseRelocationSection( 173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const Elf32_Shdr *section_header, 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AssemblyProgram* program) WARN_UNUSED_RESULT = 0; 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CheckBool ParseProgbitsSection( 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const Elf32_Shdr *section_header, 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::vector<size_t>::iterator* current_abs_offset, 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::vector<size_t>::iterator end_abs_offset, 179a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch ScopedVector<TypedRVA>::iterator* current_rel, 180a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch ScopedVector<TypedRVA>::iterator end_rel, 181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AssemblyProgram* program) WARN_UNUSED_RESULT; 182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CheckBool ParseSimpleRegion(size_t start_file_offset, 183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch size_t end_file_offset, 184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AssemblyProgram* program) WARN_UNUSED_RESULT; 185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CheckBool ParseAbs32Relocs() WARN_UNUSED_RESULT; 187ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch CheckBool CheckSection(RVA rva) WARN_UNUSED_RESULT; 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CheckBool ParseRel32RelocsFromSections() WARN_UNUSED_RESULT; 189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual CheckBool ParseRel32RelocsFromSection( 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const Elf32_Shdr* section) WARN_UNUSED_RESULT = 0; 191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Ehdr *header_; 193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Shdr *section_header_table_; 194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Half section_header_table_size_; 195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Phdr *program_header_table_; 197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Half program_header_table_size_; 198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Section header for default 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const char *default_string_section_; 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::vector<RVA> abs32_locations_; 203a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch ScopedVector<TypedRVA> rel32_locations_; 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DISALLOW_COPY_AND_ASSIGN(DisassemblerElf32); 206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace courgette 209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // COURGETTE_DISASSEMBLER_ELF_32_H_ 211