patchelf 0.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e432d8ac7a3e75e8c9e80d433bc756e635d6b4d057b7e02ed952be113c7edbf5
4
- data.tar.gz: 463cee3d6e780346706752f2a537e67fde649db82b206a8d79f15e60dd4cb4ae
3
+ metadata.gz: 8560f68dba4f9e656585c38f31da63ae5f15320a03c1675adb13d27ffa2230b4
4
+ data.tar.gz: 2d19b129beb5df7bd713fc6f0f65bb942194bea201857bda499a18e4496c4fe2
5
5
  SHA512:
6
- metadata.gz: bebe4cca89632d3660045d7582c19cf356562d2cbd389cc910377e88ea293c4fb812bb8917e89670cad05224254497c361f608e7429dcfe2c09ed94d31834a9f
7
- data.tar.gz: 849a0a0b5b8c5bc1c1e52c4f65c9452917f58cf881bca89de4a4986df0556fd677724fe1b17466ff469eed8bcada2320d69169951d9ea0ac4aed1d9be6e4d5aa
6
+ metadata.gz: a2c443a08655333dc1b97ca62c1f6803bf6971565a9b40c80554aaf89a78b8e7548f0a854dd6703175e8be57154ca541ffe71f642a35ded2a734fbe1eae83b0e
7
+ data.tar.gz: 73707a964c3cc1a9d47efcb0baaa45d1fc8e42e2450acca899b5258ca2b9236229e9e560a5c9fa347bbd7c5a429644a66ceed5ac072cb7ac06db3b98088c1a8c
data/README.md CHANGED
@@ -12,19 +12,34 @@ Implements features of NixOS/patchelf in pure Ruby.
12
12
 
13
13
  ## Installation
14
14
 
15
- WIP.
15
+ Available on RubyGems.org!
16
+ ```
17
+ $ gem install patchelf
18
+ ```
16
19
 
17
20
  ## Usage
18
21
 
19
22
  ```
20
23
  $ patchelf.rb
21
24
  # Usage: patchelf.rb <commands> FILENAME [OUTPUT_FILE]
22
- # --pi, --print-interpreter Show interpreter's name.
23
- # --pn, --print-needed Show needed libraries specified in DT_NEEDED.
24
- # --ps, --print-soname Show soname specified in DT_SONAME.
25
- # --interp, --set-interpreter INTERP
25
+ # --print-interpreter, --pi Show interpreter's name.
26
+ # --print-needed, --pn Show needed libraries specified in DT_NEEDED.
27
+ # --print-runpath, --pr Show the path specified in DT_RUNPATH.
28
+ # --print-soname, --ps Show soname specified in DT_SONAME.
29
+ # --set-interpreter, --interp INTERP
26
30
  # Set interpreter's name.
27
- # --so, --set-soname SONAME Set name of a shared library.
31
+ # --set-needed, --needed LIB1,LIB2,LIB3
32
+ # Set needed libraries, this will remove all existent needed libraries.
33
+ # --add-needed LIB Append a new needed library.
34
+ # --remove-needed LIB Remove a needed library.
35
+ # --replace-needed LIB1,LIB2 Replace needed library LIB1 as LIB2.
36
+ # --set-runpath, --runpath PATH
37
+ # Set the path of runpath.
38
+ # --force-rpath According to the ld.so docs, DT_RPATH is obsolete,
39
+ # patchelf.rb will always try to get/set DT_RUNPATH first.
40
+ # Use this option to force every operations related to runpath (e.g. --runpath)
41
+ # to consider 'DT_RPATH' instead of 'DT_RUNPATH'.
42
+ # --set-soname, --so SONAME Set name of a shared library.
28
43
  # --version Show current gem's version.
29
44
 
30
45
  ```
@@ -32,8 +47,8 @@ $ patchelf.rb
32
47
  ### Display information
33
48
  ```
34
49
  $ patchelf.rb --print-interpreter --print-needed /bin/ls
35
- # Interpreter: /lib64/ld-linux-x86-64.so.2
36
- # Needed: libselinux.so.1 libc.so.6
50
+ # interpreter: /lib64/ld-linux-x86-64.so.2
51
+ # needed: libselinux.so.1 libc.so.6
37
52
 
38
53
  ```
39
54
 
@@ -47,11 +62,54 @@ $ file ls.patch
47
62
 
48
63
  ```
49
64
 
65
+ ### Modify dependency libraries
66
+
67
+ #### Add
68
+ ```
69
+ $ patchelf.rb --add-needed libnew.so /bin/ls ls.patch
70
+ ```
71
+
72
+ #### Remove
73
+ ```
74
+ $ patchelf.rb --remove-needed libc.so.6 /bin/ls ls.patch
75
+ ```
76
+
77
+ #### Replace
78
+ ```
79
+ $ patchelf.rb --replace-needed libc.so.6,libcnew.so.6 /bin/ls ls.patch
80
+
81
+ $ readelf -d ls.patch | grep NEEDED
82
+ # 0x0000000000000001 (NEEDED) Shared library: [libselinux.so.1]
83
+ # 0x0000000000000001 (NEEDED) Shared library: [libcnew.so.6]
84
+
85
+ ```
86
+
87
+ #### Set directly
88
+ ```
89
+ $ patchelf.rb --needed a.so,b.so,c.so /bin/ls ls.patch
90
+
91
+ $ readelf -d ls.patch | grep NEEDED
92
+ # 0x0000000000000001 (NEEDED) Shared library: [a.so]
93
+ # 0x0000000000000001 (NEEDED) Shared library: [b.so]
94
+ # 0x0000000000000001 (NEEDED) Shared library: [c.so]
95
+
96
+ ```
97
+
98
+ ### Set RUNPATH of an executable
99
+ ```
100
+ $ patchelf.rb --runpath . /bin/ls ls.patch
101
+
102
+ $ readelf -d ls.patch | grep RUNPATH
103
+ # 0x000000000000001d (RUNPATH) Library runpath: [.]
104
+
105
+ ```
106
+
50
107
  ### Change SONAME of a shared library
51
108
  ```
52
- $ patchelf.rb --soname libnewname.so.217 /lib/x86_64-linux-gnu/libc.so.6 ./libc.patched
109
+ $ patchelf.rb --so libc.so.217 /lib/x86_64-linux-gnu/libc.so.6 libc.patch
53
110
 
54
- $ readelf -d libc.patched | grep SONAME
111
+ $ readelf -d libc.patch | grep SONAME
112
+ # 0x000000000000000e (SONAME) Library soname: [libc.so.217]
55
113
 
56
114
  ```
57
115
 
@@ -60,11 +118,11 @@ $ readelf -d libc.patched | grep SONAME
60
118
  require 'patchelf'
61
119
 
62
120
  patcher = PatchELF::Patcher.new('/bin/ls')
63
- patcher.get(:interpreter)
121
+ patcher.interpreter
64
122
  #=> "/lib64/ld-linux-x86-64.so.2"
65
123
 
66
124
  patcher.interpreter = '/lib/AAAA.so.2'
67
- patcher.get(:interpreter)
125
+ patcher.interpreter
68
126
  #=> "/lib/AAAA.so.2"
69
127
 
70
128
  patcher.save('ls.patch')
@@ -76,4 +134,4 @@ patcher.save('ls.patch')
76
134
 
77
135
  ## Environment
78
136
 
79
- patchelf.rb is implemented in pure Ruby, so it should work in all environments include Linux, maxOS, and Windows!
137
+ patchelf.rb is implemented in pure Ruby, so it should work in all environments include Linux, macOS, and Windows!
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'patchelf/cli'
4
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Main module of patchelf.
2
4
  #
3
5
  # @author david942j
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'optparse'
2
4
 
3
5
  require 'patchelf/patcher'
@@ -25,30 +27,50 @@ module PatchELF
25
27
  def work(argv)
26
28
  @options = {
27
29
  set: {},
28
- print: []
30
+ print: [],
31
+ needed: []
29
32
  }
30
33
  return $stdout.puts "PatchELF Version #{PatchELF::VERSION}" if argv.include?('--version')
31
34
  return $stdout.puts option_parser unless parse(argv)
32
35
 
33
36
  # Now the options are (hopefully) valid, let's process the ELF file.
34
- patcher = PatchELF::Patcher.new(@options[:in_file])
35
- # TODO: Handle ELFTools::ELFError
37
+ begin
38
+ @patcher = PatchELF::Patcher.new(@options[:in_file])
39
+ rescue ELFTools::ELFError, Errno::ENOENT => e
40
+ return PatchELF::Logger.error(e.message)
41
+ end
42
+ patcher.use_rpath! if @options[:force_rpath]
43
+ readonly
44
+ patch_requests
45
+ patcher.save(@options[:out_file])
46
+ end
47
+
48
+ private
49
+
50
+ def patcher
51
+ @patcher
52
+ end
53
+
54
+ def readonly
36
55
  @options[:print].uniq.each do |s|
37
- content = patcher.get(s)
56
+ content = patcher.__send__(s)
38
57
  next if content.nil?
39
58
 
40
- $stdout.puts "#{s.to_s.capitalize}: #{Array(content).join(' ')}"
59
+ s = :rpath if @options[:force_rpath] && s == :runpath
60
+ $stdout.puts "#{s}: #{Array(content).join(' ')}"
41
61
  end
62
+ end
42
63
 
64
+ def patch_requests
43
65
  @options[:set].each do |sym, val|
44
66
  patcher.__send__("#{sym}=".to_sym, val)
45
67
  end
46
68
 
47
- patcher.save(@options[:out_file])
69
+ @options[:needed].each do |type, val|
70
+ patcher.__send__("#{type}_needed".to_sym, *val)
71
+ end
48
72
  end
49
73
 
50
- private
51
-
52
74
  def parse(argv)
53
75
  remain = option_parser.permute(argv)
54
76
  return false if remain.first.nil?
@@ -62,23 +84,58 @@ module PatchELF
62
84
  @option_parser ||= OptionParser.new do |opts|
63
85
  opts.banner = USAGE
64
86
 
65
- opts.on('--pi', '--print-interpreter', 'Show interpreter\'s name.') do
87
+ opts.on('--print-interpreter', '--pi', 'Show interpreter\'s name.') do
66
88
  @options[:print] << :interpreter
67
89
  end
68
90
 
69
- opts.on('--pn', '--print-needed', 'Show needed libraries specified in DT_NEEDED.') do
91
+ opts.on('--print-needed', '--pn', 'Show needed libraries specified in DT_NEEDED.') do
70
92
  @options[:print] << :needed
71
93
  end
72
94
 
73
- opts.on('--ps', '--print-soname', 'Show soname specified in DT_SONAME.') do
95
+ opts.on('--print-runpath', '--pr', 'Show the path specified in DT_RUNPATH.') do
96
+ @options[:print] << :runpath
97
+ end
98
+
99
+ opts.on('--print-soname', '--ps', 'Show soname specified in DT_SONAME.') do
74
100
  @options[:print] << :soname
75
101
  end
76
102
 
77
- opts.on('--interp INTERP', '--set-interpreter INTERP', 'Set interpreter\'s name.') do |interp|
103
+ opts.on('--set-interpreter INTERP', '--interp INTERP', 'Set interpreter\'s name.') do |interp|
78
104
  @options[:set][:interpreter] = interp
79
105
  end
80
106
 
81
- opts.on('--so SONAME', '--set-soname SONAME', 'Set name of a shared library.') do |soname|
107
+ opts.on('--set-needed LIB1,LIB2,LIB3', '--needed LIB1,LIB2,LIB3', Array,
108
+ 'Set needed libraries, this will remove all existent needed libraries.') do |needs|
109
+ @options[:set][:needed] = needs
110
+ end
111
+
112
+ opts.on('--add-needed LIB', 'Append a new needed library.') do |lib|
113
+ @options[:needed] << [:add, lib]
114
+ end
115
+
116
+ opts.on('--remove-needed LIB', 'Remove a needed library.') do |lib|
117
+ @options[:needed] << [:remove, lib]
118
+ end
119
+
120
+ opts.on('--replace-needed LIB1,LIB2', Array, 'Replace needed library LIB1 as LIB2.') do |libs|
121
+ @options[:needed] << [:replace, libs]
122
+ end
123
+
124
+ opts.on('--set-runpath PATH', '--runpath PATH', 'Set the path of runpath.') do |path|
125
+ @options[:set][:runpath] = path
126
+ end
127
+
128
+ opts.on(
129
+ '--force-rpath',
130
+ 'According to the ld.so docs, DT_RPATH is obsolete,',
131
+ "#{SCRIPT_NAME} will always try to get/set DT_RUNPATH first.",
132
+ 'Use this option to force every operations related to runpath (e.g. --runpath)',
133
+ 'to consider \'DT_RPATH\' instead of \'DT_RUNPATH\'.'
134
+ ) do
135
+ @options[:force_rpath] = true
136
+ end
137
+
138
+ opts.on('--set-soname SONAME', '--so SONAME', 'Set name of a shared library.') do |soname|
82
139
  @options[:set][:soname] = soname
83
140
  end
84
141
 
@@ -0,0 +1,13 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require 'elftools/exceptions'
5
+
6
+ module PatchELF
7
+ # Raised on an error during ELF modification.
8
+ class PatchError < ELFTools::ELFError; end
9
+ # Raised when Dynamic Tag is missing
10
+ class MissingTagError < PatchError; end
11
+ # Raised on missing Program Header(segment)
12
+ class MissingSegmentError < PatchError; end
13
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module PatchELF
2
4
  # Helper methods for internal usage.
3
5
  module Helper
@@ -40,11 +42,11 @@ module PatchELF
40
42
  # @return [Integer]
41
43
  # Aligned result.
42
44
  # @example
43
- # Helper.aligndown(0x1234)
45
+ # aligndown(0x1234)
44
46
  # #=> 4096
45
- # Helper.aligndown(0x33, 0x20)
47
+ # aligndown(0x33, 0x20)
46
48
  # #=> 32
47
- # Helper.aligndown(0x10, 0x8)
49
+ # aligndown(0x10, 0x8)
48
50
  # #=> 16
49
51
  def aligndown(val, align = PAGE_SIZE)
50
52
  val - (val & (align - 1))
@@ -55,11 +57,11 @@ module PatchELF
55
57
  # @return [Integer]
56
58
  # Aligned result.
57
59
  # @example
58
- # Helper.alignup(0x1234)
60
+ # alignup(0x1234)
59
61
  # #=> 8192
60
- # Helper.alignup(0x33, 0x20)
62
+ # alignup(0x33, 0x20)
61
63
  # #=> 64
62
- # Helper.alignup(0x10, 0x8)
64
+ # alignup(0x10, 0x8)
63
65
  # #=> 16
64
66
  def alignup(val, align = PAGE_SIZE)
65
67
  (val & (align - 1)).zero? ? val : (aligndown(val, align) + align)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
 
3
5
  require 'patchelf/helper'
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'patchelf/helper'
2
- require 'patchelf/interval'
3
4
 
4
5
  module PatchELF
5
6
  # Memory management, provides malloc/free to allocate LOAD segments.
7
+ # @private
6
8
  class MM
7
- attr_reader :extend_size # @return [Integer]
8
- attr_reader :threshold # @return [Integer]
9
+ attr_reader :extend_size # @return [Integer] The size extended.
10
+ attr_reader :threshold # @return [Integer] Where the file start to be extended.
9
11
 
10
12
  # Instantiate a {MM} object.
11
13
  # @param [ELFTools::ELFFile] elf
@@ -21,9 +23,10 @@ module PatchELF
21
23
  # @yieldreturn [void]
22
24
  # One can only do the following things in the block:
23
25
  # 1. Set ELF headers' attributes (with ELFTools)
24
- # 2. Invoke {Patcher#inline_patch}
26
+ # 2. Invoke {Saver#inline_patch}
25
27
  def malloc(size, &block)
26
- # TODO: check size > 0
28
+ raise ArgumentError, 'malloc\'s size most be positive.' if size <= 0
29
+
27
30
  @request << [size, block]
28
31
  end
29
32
 
@@ -32,39 +35,21 @@ module PatchELF
32
35
  def dispatch!
33
36
  return if @request.empty?
34
37
 
35
- request_size = @request.map(&:first).inject(0, :+)
36
- # TODO: raise exception if no LOAD exists.
37
-
38
- # We're going to expand the first LOAD segment.
39
- # Sometimes there's a 'gap' between the first and the second LOAD segment,
40
- # in this case we only need to expand the first LOAD segment and remain all other things unchanged.
41
- if gap_useful?(request_size)
42
- invoke_callbacks
43
- grow_first_load(request_size)
44
- elsif extendable?(request_size)
45
- # After extended we should have large enough 'gap'.
46
-
47
- # | 1 | | 2 |
48
- # | 1 | | 2 |
49
- #=>
50
- # | 1 | | 2 |
51
- # | 1 | | 2 |
52
- # This is really dangerous..
53
- # We have to check all p_offset / sh_offset
54
- # 1. Use ELFTools to patch all headers
55
- # 2. Mark the extended size, inline_patch will behave different after this.
56
- # 3. Invoke block.call, which might copy tables and (not-allow-to-patch) strings into the gap
57
-
58
- @threshold = load_segments[1].file_head
59
- # 1.file_tail + request_size <= 2.file_head + 0x1000x
60
- @extend_size = PatchELF::Helper.alignup(request_size - gap_between_load.size)
61
- shift_attributes
62
-
63
- invoke_callbacks
64
- grow_first_load(request_size)
65
- # else
66
- # This can happen in 32bit
67
- end
38
+ @request_size = @request.map(&:first).inject(0, :+)
39
+ # The malloc-ed area must be 'rw-' since the dynamic table will be modified during runtime.
40
+ # Find all LOADs and calculate their f-gaps and m-gaps.
41
+ # We prefer f-gap since it doesn't need move the whole binaries.
42
+ # 1. Find if any f-gap has enough size, and one of the LOAD next to it is 'rw-'.
43
+ # - expand (forwardlly), only need to change the attribute of LOAD.
44
+ # 2. Do 1. again but consider m-gaps instead.
45
+ # - expand (forwardlly), need to modify all section headers.
46
+ # 3. We have to create a new LOAD, now we need to expand the first LOAD for putting new segment header.
47
+
48
+ # First of all we check if there're less than two LOADs.
49
+ abnormal_elf('No LOAD segment found, not an executable.') if load_segments.empty?
50
+ # TODO: Handle only one LOAD. (be careful if memsz > filesz)
51
+
52
+ fgap_method || mgap_method || new_load_method
68
53
  end
69
54
 
70
55
  # Query if extended.
@@ -73,7 +58,11 @@ module PatchELF
73
58
  defined?(@threshold)
74
59
  end
75
60
 
61
+ # Get correct offset after the extension.
62
+ #
63
+ # @param [Integer] off
76
64
  # @return [Integer]
65
+ # Shifted offset.
77
66
  def extended_offset(off)
78
67
  return off unless defined?(@threshold)
79
68
  return off if off < @threshold
@@ -83,37 +72,75 @@ module PatchELF
83
72
 
84
73
  private
85
74
 
86
- def gap_useful?(need_size)
87
- # Two conditions:
88
- # 1. gap is large enough
89
- gap = gap_between_load
90
- return false if gap.size < need_size
75
+ def fgap_method
76
+ idx = find_gap { |prv, nxt| nxt.file_head - prv.file_tail }
77
+ return false if idx.nil?
78
+
79
+ loads = load_segments
80
+ # prefer extend backwardly
81
+ return extend_backward(loads[idx - 1]) if writable?(loads[idx - 1])
82
+
83
+ extend_forward(loads[idx])
84
+ end
91
85
 
92
- # XXX: Do we really need this..?
93
- # If gap is enough but not all zeros, we will fail on extension..
94
- # 2. gap is all zeroes.
95
- # @elf.stream.pos = gap.head
96
- # return false unless @elf.stream.read(gap.size).bytes.inject(0, :+).zero?
86
+ def extend_backward(seg, size = @request_size)
87
+ invoke_callbacks(seg, seg.file_tail)
88
+ seg.header.p_filesz += size
89
+ seg.header.p_memsz += size
90
+ true
91
+ end
97
92
 
93
+ def extend_forward(seg, size = @request_size)
94
+ seg.header.p_offset -= size
95
+ seg.header.p_vaddr -= size
96
+ seg.header.p_filesz += size
97
+ seg.header.p_memsz += size
98
+ invoke_callbacks(seg, seg.file_head)
98
99
  true
99
100
  end
100
101
 
101
- # @return [PatchELF::Interval]
102
- def gap_between_load
103
- # We need this cache since the second LOAD might be changed
104
- return @gap_between_load if defined?(@gap_between_load)
102
+ def mgap_method
103
+ # | 1 | | 2 |
104
+ # | 1 | | 2 |
105
+ #=>
106
+ # | 1 | | 2 |
107
+ # | 1 | | 2 |
108
+ idx = find_gap(check_sz: false) { |prv, nxt| PatchELF::Helper.aligndown(nxt.mem_head) - prv.mem_tail }
109
+ return false if idx.nil?
110
+
111
+ loads = load_segments
112
+ @threshold = loads[idx].file_head
113
+ @extend_size = PatchELF::Helper.alignup(@request_size)
114
+ shift_attributes
115
+ # prefer backward than forward
116
+ return extend_backward(loads[idx - 1]) if writable?(loads[idx - 1])
117
+
118
+ # note: loads[idx].file_head has been changed in shift_attributes
119
+ extend_forward(loads[idx], @extend_size)
120
+ end
121
+
122
+ def find_gap(check_sz: true)
123
+ loads = load_segments
124
+ loads.each_with_index do |l, i|
125
+ next if i.zero?
126
+ next unless writable?(l) || writable?(loads[i - 1])
105
127
 
106
- loads = load_segments.map do |seg|
107
- PatchELF::Interval.new(seg.file_head, seg.size)
128
+ sz = yield(loads[i - 1], l)
129
+ abnormal_elf('LOAD segments are out of order.') if check_sz && sz.negative?
130
+ next unless sz >= @request_size
131
+
132
+ return i
108
133
  end
109
- # TODO: raise if loads.min != loads.first
134
+ nil
135
+ end
136
+
137
+ # TODO
138
+ def new_load_method
139
+ raise NotImplementedError
140
+ end
110
141
 
111
- loads.sort!
112
- # Only one LOAD, the gap has infinity size!
113
- size = if loads.size == 1 then Float::INFINITY
114
- else loads[1].head - loads.first.tail
115
- end
116
- @gap_between_load = PatchELF::Interval.new(loads.first.tail, size)
142
+ def writable?(seg)
143
+ seg.readable? && seg.writable?
117
144
  end
118
145
 
119
146
  # For all attributes >= threshold, += offset
@@ -123,14 +150,18 @@ module PatchELF
123
150
  # all
124
151
  # Segments:
125
152
  # all
126
- # XXX: will be buggy if one day the number of segments might be changed.
153
+ # XXX: will be buggy if someday the number of segments can be changed.
127
154
 
128
155
  # Bottom-up
129
156
  @elf.each_sections do |sec|
130
157
  sec.header.sh_offset += extend_size if sec.header.sh_offset >= threshold
131
158
  end
132
159
  @elf.each_segments do |seg|
133
- seg.header.p_offset += extend_size if seg.header.p_offset >= threshold
160
+ next unless seg.header.p_offset >= threshold
161
+
162
+ seg.header.p_offset += extend_size
163
+ # We have to change align of LOAD segment since ld.so checks it.
164
+ seg.header.p_align = Helper::PAGE_SIZE if seg.is_a?(ELFTools::Segments::LoadSegment)
134
165
  end
135
166
 
136
167
  @elf.header.e_shoff += extend_size if @elf.header.e_shoff >= threshold
@@ -140,28 +171,16 @@ module PatchELF
140
171
  @elf.segments_by_type(:load)
141
172
  end
142
173
 
143
- def extendable?(request_size)
144
- loads = load_segments
145
- # We can assume loads.size >= 2 because
146
- # 0: has raised an exception before
147
- # 1: the gap must be used, nobody cares extendable size.
148
- # Calcluate the max size of the first LOAD segment can be.
149
- PatchELF::Helper.aligndown(loads[1].mem_head) - loads.first.mem_tail >= request_size
150
- end
151
-
152
- def invoke_callbacks
153
- seg = load_segments.first
154
- cur = gap_between_load.head
174
+ def invoke_callbacks(seg, start)
175
+ cur = start
155
176
  @request.each do |sz, block|
156
177
  block.call(cur, seg.offset_to_vma(cur))
157
178
  cur += sz
158
179
  end
159
180
  end
160
181
 
161
- def grow_first_load(size)
162
- seg = load_segments.first
163
- seg.header.p_filesz += size
164
- seg.header.p_memsz += size
182
+ def abnormal_elf(msg)
183
+ raise ArgumentError, msg
165
184
  end
166
185
  end
167
186
  end