Skip to content

Commit 50780db

Browse files
committed
Introduced LoadSegment
1 parent a074e3f commit 50780db

File tree

7 files changed

+104
-4
lines changed

7 files changed

+104
-4
lines changed

lib/elftools/elf_file.rb

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,7 @@ def segment_at(n)
290290
# #=> 4919 # 0x1337
291291
def offset_from_vma(vma, size = 0)
292292
segments_by_type(:load) do |seg|
293-
if vma >= (seg.header.p_vaddr & -seg.header.p_align) &&
294-
vma + size <= seg.header.p_vaddr + seg.header.p_filesz
295-
return vma - seg.header.p_vaddr + seg.header.p_offset
296-
end
293+
return seg.vma_to_offset(vma) if seg.vma_in?(vma, size)
297294
end
298295
end
299296

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
require 'elftools/segments/segment'
2+
3+
module ELFTools
4+
module Segments
5+
# For DT_LOAD segment.
6+
# Able to query between file offset and virtual memory address.
7+
class LoadSegment < Segment
8+
# Returns the start of this segment.
9+
# @return [Integer]
10+
# The file offset.
11+
def file_head
12+
header.p_offset.to_i
13+
end
14+
15+
# Returns size in file.
16+
# @return [Integer]
17+
# The size.
18+
def size
19+
header.p_filesz.to_i
20+
end
21+
22+
# Returns the end of this segment.
23+
# @return [Integer]
24+
# The file offset.
25+
def file_tail
26+
file_head + size
27+
end
28+
29+
# Returns the start virtual address of this segment.
30+
# @return [Integer]
31+
# The vma.
32+
def mem_head
33+
header.p_vaddr.to_i
34+
end
35+
36+
# Returns size in memory.
37+
# @return [Integer]
38+
# The size.
39+
def mem_size
40+
header.p_memsz.to_i
41+
end
42+
43+
# Returns the end virtual address of this segment.
44+
# @return [Integer]
45+
# The vma.
46+
def mem_tail
47+
mem_head + mem_size
48+
end
49+
50+
# Query if the given file offset located in this segment.
51+
# @param [Integer] offset
52+
# File offset.
53+
# @param [Integer] size
54+
# Size.
55+
# @return [Boolean]
56+
def offset_in?(offset, size = 0)
57+
file_head <= offset && offset + size < file_tail
58+
end
59+
60+
# Convert file offset into virtual memory address.
61+
# @param [Integer] offset
62+
# File offset.
63+
# @return [Integer]
64+
def offset_to_vma(offset)
65+
# XXX: What if file_head is not aligned with p_vaddr (which is invalid according to ELF spec)?
66+
offset - file_head + header.p_vaddr
67+
end
68+
69+
# Query if the given virtual memory address located in this segment.
70+
# @param [Integer] vma
71+
# Virtual memory address.
72+
# @param [Integer] size
73+
# Size.
74+
# @return [Boolean]
75+
def vma_in?(vma, size = 0)
76+
vma >= (header.p_vaddr & -header.p_align) &&
77+
vma + size <= mem_tail
78+
end
79+
80+
# Convert virtual memory address into file offset.
81+
# @param [Integer] vma
82+
# Virtual memory address.
83+
# @return [Integer]
84+
def vma_to_offset(vma)
85+
vma - header.p_vaddr + header.p_offset
86+
end
87+
end
88+
end
89+
end

lib/elftools/segments/segments.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
require 'elftools/segments/dynamic_segment'
66
require 'elftools/segments/interp_segment'
7+
require 'elftools/segments/load_segment'
78
require 'elftools/segments/note_segment'
89

910
module ELFTools
@@ -20,6 +21,7 @@ def create(header, stream, *args)
2021
klass = case header.p_type
2122
when Constants::PT_DYNAMIC then DynamicSegment
2223
when Constants::PT_INTERP then InterpSegment
24+
when Constants::PT_LOAD then LoadSegment
2325
when Constants::PT_NOTE then NoteSegment
2426
else Segment
2527
end

spec/full_test/i386_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,7 @@
2626
expect(@elf.segment_by_type(:interp).interp_name).to eq '/lib/ld-linux.so.2'
2727
expect(@elf.segment_by_type(:note).notes.size).to be 2
2828
expect(@elf.segment_by_type(:gnu_stack).executable?).to be false
29+
expect(@elf.segment_by_type(:load).offset_in?(0x12345678)).to be false
30+
expect(@elf.segment_by_type(:load).offset_to_vma(0)).to be 0x8048000
2931
end
3032
end

spec/full_test/pie_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,7 @@
2424
expect(@elf.segment_by_type(:interp).interp_name).to eq '/lib/ld-linux.so.2'
2525
expect(@elf.segment_by_type(:note).notes.size).to be 2
2626
expect(@elf.segment_by_type(:gnu_stack).executable?).to be false
27+
expect(@elf.segment_by_type(:load).offset_in?(0x12345678)).to be false
28+
expect(@elf.segment_by_type(:load).offset_to_vma(0x33)).to be 0x33
2729
end
2830
end

spec/full_test/striped_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,7 @@
2323
expect(@elf.segment_by_type(:interp).interp_name).to eq '/lib64/ld-linux-x86-64.so.2'
2424
expect(@elf.segment_by_type(:note).notes.size).to be 2
2525
expect(@elf.segment_by_type(:gnu_stack).executable?).to be false
26+
expect(@elf.segment_by_type(:load).offset_in?(0x33)).to be true
27+
expect(@elf.segment_by_type(:load).offset_to_vma(0x33)).to be 0x400033
2628
end
2729
end

spec/segments_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636
expect(dynamic).to be_a ELFTools::Segments::DynamicSegment
3737
expect(dynamic.respond_to?(:tags)).to be true
3838
end
39+
40+
it 'load' do
41+
load_seg = ELFTools::Segments::Segment.create(@header_maker.call(type: 1), nil)
42+
expect(load_seg).to be_a ELFTools::Segments::LoadSegment
43+
expect(load_seg.respond_to?(:vma_to_offset)).to be true
44+
end
3945
end
4046

4147
describe 'common methods' do

0 commit comments

Comments
 (0)