Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

support relocation info

  • Loading branch information...
commit ce1f5bb4dcc65f7005ab6f99650bf98042b89435 1 parent 0269598
Sami Samhuri authored

Showing 1 changed file with 57 additions and 50 deletions. Show diff stats Hide diff stats

  1. 107  asm/machofile.rb
107  asm/machofile.rb
@@ -8,16 +8,20 @@ class MachOFile
8 8
     
9 9
     attr_accessor :header, :load_commands, :sections, :data
10 10
     attr_accessor :current_segment
11  
-    attr_accessor :text_offset
12 11
     
13 12
     def initialize(filetype=MH_OBJECT)
14 13
       @header = MachHeader.new(MH_MAGIC, CPU_TYPE_X86, CPU_SUBTYPE_X86_ALL, filetype, 0, 0, 0)
15 14
       @load_commands = []              # All defined segments.
16  
-      @sections = {}                   # Map of segment names to lists of segments. 
  15
+      @sections = {}                   # Map of segment names to lists of sections. 
17 16
       @section_disk_size = Hash.new(0) # Sections store their VM size so we need their sizes on disk.
  17
+      @section_offset = 0              # Offset of the next section's data, in bytes.
18 18
       @data = []                       # Blobs of data that appear at the end of the file.
19  
-                                       #   (text, data, symtab, ...)
  19
+                                       #  (text, data, relocation info, symtab, ...)
20 20
       @current_segment = nil           # An alias for the last defined segment.
  21
+      @text_segname = nil              # Name of __TEXT segement
  22
+      @text_sect_index = nil           # Index of __text section
  23
+      @text_data_index = nil           # Index into @data of __text section data
  24
+      @reloc_info = nil                # Copy of relocation info array
21 25
     end
22 26
 
23 27
 
@@ -82,11 +86,12 @@ def section(name, segname, data='', vmsize=data.size,
82 86
                 segment=@current_segment, type=S_REGULAR)
83 87
       
84 88
       # Create the new section.
85  
-      section = Section.new(name, segname, 0, vmsize, 0, 0, 0, 0, 0, 0, type)
  89
+      section = Section.new(name, segname, @section_offset, vmsize, 0, 0, 0, 0, 0, 0, type)
86 90
       
87 91
       # Add this section to the map of segment names to sections.
88 92
       (@sections[segment[:segname]] ||= []) << section
89 93
       @section_disk_size[name] = data.size
  94
+      @section_offset += data.size
90 95
       @data << data if data.size > 0
91 96
       
92 97
       # Update the header.
@@ -116,20 +121,32 @@ def section(name, segname, data='', vmsize=data.size,
116 121
     # name given (__TEXT).
117 122
     
118 123
     def text(data, sectname='__text', segname='__TEXT')
  124
+      real_segname = nil
119 125
       unless @current_segment
120  
-        segment(segname_based_on_filetype(segname)) do |seg|
  126
+        real_segname = segname_based_on_filetype(segname)
  127
+        segment(real_segname) do |seg|
121 128
           seg[:maxprot] = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE
122 129
           seg[:initprot] = VM_PROT_READ | VM_PROT_EXECUTE
123  
-        end        
  130
+        end
124 131
       end
125 132
       
126 133
       section(sectname, segname, data) do |sect|
  134
+        # reloff and nreloc are calculated later (in calculate_offsets)
127 135
         sect[:flags] = 0x400 # S_ATTR_SOME_INSTRUCTIONS
128 136
       end
  137
+
  138
+      # Remember where section and data are so we can update them later.
  139
+      @text_segname = real_segname || segname
  140
+      @text_sect_index = @sections[@text_segname].length-1
  141
+      @text_data_index = @data.length-1
129 142
       
130 143
       return self
131 144
     end
132 145
 
  146
+    def update_text(data)
  147
+      raise 'no __text segment defined yet' unless @text_data_index
  148
+      @data[@text_data_index] = data
  149
+    end
133 150
 
134 151
     # Basis for #data, #const, and #bss methods.
135 152
     def segment_based_on_filetype(segname, options={})
@@ -173,6 +190,19 @@ def bss(vmsize, sectname='__bss', segname='__DATA')
173 190
       end
174 191
     end
175 192
 
  193
+    # Define a relocation table. Usually between segments and the
  194
+    # symbol table.
  195
+    #
  196
+    # Accepts an array of relocation info structs.
  197
+    def reloc(reloc_info)
  198
+      @data << if reloc_info.respond_to?(:join)
  199
+                 reloc_info.map {|r| r.serialize}.join
  200
+               else
  201
+                 reloc_info
  202
+               end
  203
+      @reloc_info = reloc_info.map {|x| x.clone}
  204
+      return self
  205
+    end
176 206
    
177 207
     # Define a symbol table.  This should usually be placed at the end of the
178 208
     # file.
@@ -204,7 +234,6 @@ def symtab(nlist_ary_or_symtab, stab=nil)
204 234
       
205 235
       @data << nlist_ary.map {|n| n.serialize}.join
206 236
       @data << stab
207  
-      
208 237
       return self
209 238
     end
210 239
 
@@ -218,63 +247,34 @@ def serialize
218 247
       
219 248
       # Now that we have all the pieces of the file defined we can calculate
220 249
       # the file offsets of segments and sections.
221  
-      recalculate_offsets
222  
-
223  
-      
224  
-      # |------------------|
225  
-      # |  Mach Header     |          Part 1
226  
-      # |------------------|
227  
-      # |  Segment 1       |          Part 2
228  
-      # |    Section 1     | ---
229  
-      # |    Section 2     | --|--
230  
-      # |    ...           |   | |
231  
-      # |  Segment 2       |   | |
232  
-      # |    Section 4     |   | |
233  
-      # |    Section 5     |   | |
234  
-      # |    ...           |   | |
235  
-      # |  ...             |   | |
236  
-      # |  [Symtab cmd]    |   | |
237  
-      # |------------------|   | |
238  
-      # |  Section data 1  | <-- |    Part 3
239  
-      # |  Section data 2  | <----
240  
-      # |  ...             |
241  
-      # |  [Symtab data]   |
242  
-      # |------------------|      
  250
+      calculate_offsets
243 251
 
244 252
       ###################################
245 253
       # Mach-O file Part 1: Mach Header #
246 254
       ###################################
  255
+      @header.serialize +
247 256
 
248  
-      obj = @header.serialize
249  
-
250  
-      
251 257
       #####################################
252 258
       # Mach-O file Part 2: Load Commands #
253 259
       #####################################
254  
-
255 260
       # dump each load command (which include the section headers under them)
256  
-      obj += @load_commands.map do |cmd|               
257  
-               sects = @sections[cmd[:segname]] rescue []
258  
-               sects.inject(cmd.serialize) do |data, sect|
259  
-                 data + sect.serialize
260  
-               end
261  
-            end.join
262  
-      
  261
+      @load_commands.map do |cmd|               
  262
+        sects = @sections[cmd[:segname]] rescue []
  263
+        sects.inject(cmd.serialize) do |data, sect|
  264
+          data + sect.serialize
  265
+        end
  266
+      end.join +
263 267
 
264 268
       ###################################
265 269
       # Mach-O file Part 3: Binary data #
266 270
       ###################################
267  
-
268  
-      obj += @data.join
269  
-
270  
-      
271  
-      return obj
  271
+      @data.join
272 272
     end
273 273
 
274 274
     
275 275
     # Update the file offsets in segments and sections.
276 276
     
277  
-    def recalculate_offsets
  277
+    def calculate_offsets
278 278
 
279 279
       # Maintain the offset into the the file on disk.  This is used
280 280
       # to update the various structures.
@@ -317,7 +317,7 @@ def recalculate_offsets
317 317
 
318 318
       # Second pass over load commands.  Fill in file offsets.
319 319
       @load_commands.each do |cmd|
320  
-        case cmd[:cmd]\
  320
+        case cmd[:cmd]
321 321
           
322 322
         when LC_SEGMENT
323 323
           seg = cmd
@@ -329,6 +329,13 @@ def recalculate_offsets
329 329
           end
330 330
           
331 331
         when LC_SYMTAB
  332
+          if @reloc_info
  333
+            # update text section with relocation info
  334
+            __text = @sections[@text_segname][@text_sect_index]
  335
+            __text[:reloff] = offset
  336
+            __text[:nreloc] = @reloc_info.length
  337
+            offset += @reloc_info.first.bytesize * @reloc_info.length
  338
+          end
332 339
           st = cmd
333 340
           st[:symoff] = offset
334 341
           offset += st[:nsyms] * Nlist.bytesize
@@ -341,8 +348,8 @@ def recalculate_offsets
341 348
         end
342 349
         
343 350
       end # @load_commands.each
344  
-      
345  
-    end # def recalculate_offsets
  351
+
  352
+    end # def calculate_offsets
346 353
   
347 354
   
348 355
     #######
@@ -354,7 +361,7 @@ def segname_based_on_filetype(segname)
354 361
       when MH_OBJECT: ''
355 362
       when MH_EXECUTE: segname
356 363
       else
357  
-        raise "unsupported MachO file type! #{@header.inspect}"
  364
+        raise "unsupported MachO file type: #{@header.inspect}"
358 365
       end
359 366
     end
360 367
     

0 notes on commit ce1f5bb

Please sign in to comment.
Something went wrong with that request. Please try again.