1 // Copyright (c) 2012 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 "courgette/disassembler_elf_32_x86.h"
11 #include "base/basictypes.h"
12 #include "base/logging.h"
14 #include "courgette/assembly_program.h"
15 #include "courgette/courgette.h"
16 #include "courgette/encoded_program.h"
20 DisassemblerElf32X86::DisassemblerElf32X86(const void* start
, size_t length
)
21 : DisassemblerElf32(start
, length
) {
24 // Convert an ELF relocation struction into an RVA
25 CheckBool
DisassemblerElf32X86::RelToRVA(Elf32_Rel rel
, RVA
* result
) const {
27 // The rightmost byte of r_info is the type...
28 elf32_rel_386_type_values type
=
29 (elf32_rel_386_type_values
)(unsigned char)rel
.r_info
;
31 // The other 3 bytes of r_info are the symbol
32 uint32 symbol
= rel
.r_info
>> 8;
50 // This is a basic ABS32 relocation address
51 *result
= rel
.r_offset
;
63 CheckBool
DisassemblerElf32X86::ParseRelocationSection(
64 const Elf32_Shdr
*section_header
,
65 AssemblyProgram
* program
) {
66 // We can reproduce the R_386_RELATIVE entries in one of the relocation
67 // table based on other information in the patch, given these
70 // All R_386_RELATIVE entries are:
71 // 1) In the same relocation table
73 // 3) Are sorted in memory address order
75 // Happily, this is normally the case, but it's not required by spec
76 // so we check, and just don't do it if we don't match up.
78 // The expectation is that one relocation section will contain
79 // all of our R_386_RELATIVE entries in the expected order followed
80 // by assorted other entries we can't use special handling for.
84 // Walk all the bytes in the section, matching relocation table or not
85 size_t file_offset
= section_header
->sh_offset
;
86 size_t section_end
= section_header
->sh_offset
+ section_header
->sh_size
;
88 Elf32_Rel
*section_relocs_iter
=
89 (Elf32_Rel
*)OffsetToPointer(section_header
->sh_offset
);
91 uint32 section_relocs_count
= section_header
->sh_size
/
92 section_header
->sh_entsize
;
94 if (abs32_locations_
.size() > section_relocs_count
)
97 std::vector
<RVA
>::iterator reloc_iter
= abs32_locations_
.begin();
99 while (match
&& (reloc_iter
!= abs32_locations_
.end())) {
100 if (section_relocs_iter
->r_info
!= R_386_RELATIVE
||
101 section_relocs_iter
->r_offset
!= *reloc_iter
)
103 section_relocs_iter
++;
108 // Skip over relocation tables
109 if (!program
->EmitElfRelocationInstruction())
111 file_offset
+= sizeof(Elf32_Rel
) * abs32_locations_
.size();
114 return ParseSimpleRegion(file_offset
, section_end
, program
);
117 CheckBool
DisassemblerElf32X86::ParseRel32RelocsFromSection(
118 const Elf32_Shdr
* section_header
) {
120 uint32 start_file_offset
= section_header
->sh_offset
;
121 uint32 end_file_offset
= start_file_offset
+ section_header
->sh_size
;
123 const uint8
* start_pointer
= OffsetToPointer(start_file_offset
);
124 const uint8
* end_pointer
= OffsetToPointer(end_file_offset
);
126 // Quick way to convert from Pointer to RVA within a single Section is to
127 // subtract 'pointer_to_rva'.
128 const uint8
* const adjust_pointer_to_rva
= start_pointer
-
129 section_header
->sh_addr
;
131 // Find the rel32 relocations.
132 const uint8
* p
= start_pointer
;
133 while (p
< end_pointer
) {
134 //RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva);
136 // Heuristic discovery of rel32 locations in instruction stream: are the
137 // next few bytes the start of an instruction containing a rel32
139 const uint8
* rel32
= NULL
;
141 if (p
+ 5 <= end_pointer
) {
142 if (*p
== 0xE8 || *p
== 0xE9) { // jmp rel32 and call rel32
146 if (p
+ 6 <= end_pointer
) {
147 if (*p
== 0x0F && (*(p
+1) & 0xF0) == 0x80) { // Jcc long form
148 if (p
[1] != 0x8A && p
[1] != 0x8B) // JPE/JPO unlikely
153 RVA rva
= static_cast<RVA
>(rel32
- adjust_pointer_to_rva
);
154 TypedRVAX86
* rel32_rva
= new TypedRVAX86(rva
);
156 if (!rel32_rva
->ComputeRelativeTarget(rel32
)) {
160 RVA target_rva
= rel32_rva
->rva() + rel32_rva
->relative_target();
161 // To be valid, rel32 target must be within image, and within this
163 if (IsValidRVA(target_rva
)) {
164 rel32_locations_
.push_back(rel32_rva
);
165 #if COURGETTE_HISTOGRAM_TARGETS
166 ++rel32_target_rvas_
[target_rva
];
180 } // namespace courgette