Class: MachO::MachOFile

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/macho/macho_file.rb

Overview

Represents a Mach-O file, which contains a header and load commands as well as binary executable instructions. Mach-O binaries are architecture specific.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filename, **opts) ⇒ MachOFile

Note:

The :decompress option relies on non-default dependencies. Compression is only used in niche Mach-Os, so leaving this disabled is a reasonable default for virtually all normal uses.

Creates a new instance from data read from the given filename.

Parameters:

  • filename (String)

    the Mach-O file to load from

  • opts (Hash)

    options to control the parser with

Options Hash (**opts):

  • :permissive (Boolean)

    whether to ignore unknown load commands

  • :decompress (Boolean)

    whether to decompress, if capable

Raises:

  • (ArgumentError)

    if the given file does not exist



58
59
60
61
62
63
64
65
# File 'lib/macho/macho_file.rb', line 58

def initialize(filename, **opts)
  raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)

  @filename = filename
  @options = opts
  @raw_data = File.binread(@filename)
  populate_fields
end

Instance Attribute Details

#endiannessSymbol (readonly)

Returns the endianness of the file, :big or :little.

Returns:

  • (Symbol)

    the endianness of the file, :big or :little



22
23
24
# File 'lib/macho/macho_file.rb', line 22

def endianness
  @endianness
end

#filenameString?

Returns the filename loaded from, or nil if loaded from a binary string.

Returns:

  • (String, nil)

    the filename loaded from, or nil if loaded from a binary string



16
17
18
# File 'lib/macho/macho_file.rb', line 16

def filename
  @filename
end

#headerHeaders::MachHeader, Headers::MachHeader64 (readonly)

Returns:



26
27
28
# File 'lib/macho/macho_file.rb', line 26

def header
  @header
end

#load_commandsArray<LoadCommands::LoadCommand> (readonly)

Note:

load commands are provided in order of ascending offset.

Returns an array of the file's load commands.

Returns:



31
32
33
# File 'lib/macho/macho_file.rb', line 31

def load_commands
  @load_commands
end

#optionsHash (readonly)

Returns any parser options that the instance was created with.

Returns:

  • (Hash)

    any parser options that the instance was created with



19
20
21
# File 'lib/macho/macho_file.rb', line 19

def options
  @options
end

Class Method Details

.new_from_bin(bin, **opts) ⇒ MachOFile

Note:

The :decompress option relies on non-default dependencies. Compression is only used in niche Mach-Os, so leaving this disabled is a reasonable default for virtually all normal uses.

Creates a new instance from a binary string.

Parameters:

  • bin (String)

    a binary string containing raw Mach-O data

  • opts (Hash)

    options to control the parser with

Options Hash (**opts):

  • :permissive (Boolean)

    whether to ignore unknown load commands

  • :decompress (Boolean)

    whether to decompress, if capable

Returns:



42
43
44
45
46
47
# File 'lib/macho/macho_file.rb', line 42

def self.new_from_bin(bin, **opts)
  instance = allocate
  instance.initialize_from_bin(bin, opts)

  instance
end

Instance Method Details

#add_command(lc, options = {}) ⇒ void

Note:

This is public, but methods like #add_rpath should be preferred. Setting repopulate to false will leave the instance in an inconsistent state unless #populate_fields is called immediately afterwards.

This method returns an undefined value.

Appends a new load command to the Mach-O.

Parameters:

  • lc (LoadCommands::LoadCommand)

    the load command being added

  • options (Hash) (defaults to: {})
  • f (Hash)

    a customizable set of options

See Also:



215
216
217
# File 'lib/macho/macho_file.rb', line 215

def add_command(lc, options = {})
  insert_command(header.class.bytesize + sizeofcmds, lc, options)
end

#add_rpath(path, _options = {}) ⇒ void

Note:

_options is currently unused and is provided for signature compatibility with FatFile#add_rpath

This method returns an undefined value.

Add the given runtime path to the Mach-O.

Examples:

file.rpaths # => ["/lib"]
file.add_rpath("/usr/lib")
file.rpaths # => ["/lib", "/usr/lib"]

Parameters:

  • path (String)

    the new runtime path

  • _options (Hash) (defaults to: {})

Raises:



405
406
407
408
409
410
# File 'lib/macho/macho_file.rb', line 405

def add_rpath(path, _options = {})
  raise RpathExistsError, path if rpaths.include?(path)

  rpath_cmd = LoadCommands::LoadCommand.create(:LC_RPATH, path)
  add_command(rpath_cmd)
end

#alignmentInteger

Returns the file's internal alignment.

Returns:

  • (Integer)

    the file's internal alignment



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#bundle?Boolean

Returns whether or not the file is of type MH_BUNDLE.

Returns:

  • (Boolean)

    whether or not the file is of type MH_BUNDLE



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#change_dylib_id(new_id, _options = {}) ⇒ void Also known as: dylib_id=

Note:

_options is currently unused and is provided for signature compatibility with FatFile#change_dylib_id

This method returns an undefined value.

Changes the Mach-O's dylib ID to new_id. Does nothing if not a dylib.

Examples:

file.change_dylib_id("libFoo.dylib")

Parameters:

  • new_id (String)

    the dylib's new ID

  • _options (Hash) (defaults to: {})

Raises:

  • (ArgumentError)

    if new_id is not a String



317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/macho/macho_file.rb', line 317

def change_dylib_id(new_id, _options = {})
  raise ArgumentError, "new ID must be a String" unless new_id.is_a?(String)
  return unless dylib?

  old_lc = command(:LC_ID_DYLIB).first
  raise DylibIdMissingError unless old_lc

  new_lc = LoadCommands::LoadCommand.create(:LC_ID_DYLIB, new_id,
                                            old_lc.timestamp,
                                            old_lc.current_version,
                                            old_lc.compatibility_version)

  replace_command(old_lc, new_lc)
end

#change_install_name(old_name, new_name, _options = {}) ⇒ void Also known as: change_dylib

Note:

_options is currently unused and is provided for signature compatibility with FatFile#change_install_name

This method returns an undefined value.

Changes the shared library old_name to new_name

Examples:

file.change_install_name("abc.dylib", "def.dylib")

Parameters:

  • old_name (String)

    the shared library's old name

  • new_name (String)

    the shared library's new name

  • _options (Hash) (defaults to: {})

Raises:



354
355
356
357
358
359
360
361
362
363
364
# File 'lib/macho/macho_file.rb', line 354

def change_install_name(old_name, new_name, _options = {})
  old_lc = dylib_load_commands.find { |d| d.name.to_s == old_name }
  raise DylibUnknownError, old_name if old_lc.nil?

  new_lc = LoadCommands::LoadCommand.create(old_lc.type, new_name,
                                            old_lc.timestamp,
                                            old_lc.current_version,
                                            old_lc.compatibility_version)

  replace_command(old_lc, new_lc)
end

#change_rpath(old_path, new_path, options = {}) ⇒ void

This method returns an undefined value.

Changes the runtime path old_path to new_path

Examples:

file.change_rpath("/usr/lib", "/usr/local/lib")

Parameters:

  • old_path (String)

    the old runtime path

  • new_path (String)

    the new runtime path

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :uniq (Boolean) — default: false

    if true, change duplicate rpaths simultaneously.

Raises:



384
385
386
387
388
389
390
391
392
# File 'lib/macho/macho_file.rb', line 384

def change_rpath(old_path, new_path, options = {})
  old_lc = command(:LC_RPATH).find { |r| r.path.to_s == old_path }
  raise RpathUnknownError, old_path if old_lc.nil?

  new_lc = LoadCommands::LoadCommand.create(:LC_RPATH, new_path)

  delete_rpath(old_path, options)
  insert_command(old_lc.view.offset, new_lc)
end

#command(name) ⇒ Array<LoadCommands::LoadCommand> Also known as: []

All load commands of a given name.

Examples:

file.command("LC_LOAD_DYLIB")
file[:LC_LOAD_DYLIB]

Parameters:

  • name (String, Symbol)

    the load command ID

Returns:



149
150
151
# File 'lib/macho/macho_file.rb', line 149

def command(name)
  load_commands.select { |lc| lc.type == name.to_sym }
end

#core?Boolean

Returns whether or not the file is of type MH_CORE.

Returns:

  • (Boolean)

    whether or not the file is of type MH_CORE



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#cpusubtypeSymbol

Returns a symbol representation of the Mach-O's CPU subtype.

Returns:

  • (Symbol)

    a symbol representation of the Mach-O's CPU subtype



138
139
140
# File 'lib/macho/macho_file.rb', line 138

def cpusubtype
  Headers::CPU_SUBTYPES[header.cputype][header.cpusubtype]
end

#cputypeSymbol

Returns a symbol representation of the Mach-O's CPU type.

Returns:

  • (Symbol)

    a symbol representation of the Mach-O's CPU type



133
134
135
# File 'lib/macho/macho_file.rb', line 133

def cputype
  Headers::CPU_TYPES[header.cputype]
end

#delete_command(lc, options = {}) ⇒ void

Note:

This is public, but methods like #delete_rpath should be preferred. Setting repopulate to false will leave the instance in an inconsistent state unless #populate_fields is called immediately afterwards.

This method returns an undefined value.

Delete a load command from the Mach-O.

Parameters:

Options Hash (options):

  • :repopulate (Boolean) — default: true

    whether or not to repopulate the instance fields



229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/macho/macho_file.rb', line 229

def delete_command(lc, options = {})
  @raw_data.slice!(lc.view.offset, lc.cmdsize)

  # update Mach-O header fields to account for deleted load command
  update_ncmds(ncmds - 1)
  update_sizeofcmds(sizeofcmds - lc.cmdsize)

  # pad the space after the load commands to preserve offsets
  @raw_data.insert(header.class.bytesize + sizeofcmds - lc.cmdsize, Utils.nullpad(lc.cmdsize))

  populate_fields if options.fetch(:repopulate, true)
end

#delete_rpath(path, options = {}) ⇒ Object

Delete the given runtime path from the Mach-O.

Examples:

file1.rpaths # => ["/lib", "/usr/lib", "/lib"]
file1.delete_rpath("/lib")
file1.rpaths # => ["/usr/lib", "/lib"]
file2.rpaths # => ["foo", "foo"]
file2.delete_rpath("foo", :uniq => true)
file2.rpaths # => []
file3.rpaths # => ["foo", "bar", "foo"]
file3.delete_rpath("foo", :last => true)
file3.rpaths # => ["foo", "bar"]

Parameters:

  • path (String)

    the runtime path to delete

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :uniq (Boolean) — default: false

    if true, also delete duplicates of the requested path. If false, delete the first instance (by offset) of the requested path, unless :last is true. Incompatible with :last.

  • :last (Boolean) — default: false

    if true, delete the last instance (by offset) of the requested path. Incompatible with :uniq.

Returns:

  • void

Raises:

  • (RpathUnknownError)

    if no such runtime path exists

  • (ArgumentError)

    if both :uniq and :last are true



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'lib/macho/macho_file.rb', line 434

def delete_rpath(path, options = {})
  uniq = options.fetch(:uniq, false)
  last = options.fetch(:last, false)
  raise ArgumentError, "Cannot set both :uniq and :last to true" if uniq && last

  search_method = uniq || last ? :select : :find
  rpath_cmds = command(:LC_RPATH).public_send(search_method) { |r| r.path.to_s == path }
  rpath_cmds = rpath_cmds.last if last

  # Cast rpath_cmds into an Array so we can handle the uniq and non-uniq cases the same way
  rpath_cmds = Array(rpath_cmds)
  raise RpathUnknownError, path if rpath_cmds.empty?

  # delete the commands in reverse order, offset descending.
  rpath_cmds.reverse_each { |cmd| delete_command(cmd) }
end

#dsym?Boolean

Returns whether or not the file is of type MH_DSYM.

Returns:

  • (Boolean)

    whether or not the file is of type MH_DSYM



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#dylib?Boolean

Returns whether or not the file is of type MH_DYLIB.

Returns:

  • (Boolean)

    whether or not the file is of type MH_DYLIB



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#dylib_idString?

The Mach-O's dylib ID, or nil if not a dylib.

Examples:

file.dylib_id # => 'libBar.dylib'

Returns:

  • (String, nil)

    the Mach-O's dylib ID



300
301
302
303
304
305
306
# File 'lib/macho/macho_file.rb', line 300

def dylib_id
  return unless dylib?

  dylib_id_cmd = command(:LC_ID_DYLIB).first

  dylib_id_cmd.name.to_s
end

#dylib_load_commandsArray<LoadCommands::DylibCommand>

All load commands responsible for loading dylibs.

Returns:



254
255
256
# File 'lib/macho/macho_file.rb', line 254

def dylib_load_commands
  load_commands.select { |lc| LoadCommands::DYLIB_LOAD_COMMANDS.include?(lc.type) }
end

#dylinker?Boolean

Returns whether or not the file is of type MH_DYLINKER.

Returns:

  • (Boolean)

    whether or not the file is of type MH_DYLINKER



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#executable?Boolean

Returns whether or not the file is of type MH_EXECUTE.

Returns:

  • (Boolean)

    whether or not the file is of type MH_EXECUTE



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#filetypeSymbol

Returns a string representation of the Mach-O's filetype.

Returns:

  • (Symbol)

    a string representation of the Mach-O's filetype



128
129
130
# File 'lib/macho/macho_file.rb', line 128

def filetype
  Headers::MH_FILETYPES[header.filetype]
end

#flagsInteger

Returns the header flags associated with the Mach-O.

Returns:

  • (Integer)

    the header flags associated with the Mach-O



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#fvmlib?Boolean

Returns whether or not the file is of type MH_FVMLIB.

Returns:

  • (Boolean)

    whether or not the file is of type MH_FVMLIB



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#initialize_from_bin(bin, opts) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initializes a new MachOFile instance from a binary string with the given options.

See Also:



70
71
72
73
74
75
# File 'lib/macho/macho_file.rb', line 70

def initialize_from_bin(bin, opts)
  @filename = nil
  @options = opts
  @raw_data = bin
  populate_fields
end

#insert_command(offset, lc, options = {}) ⇒ Object

Note:

Calling this method with an arbitrary offset in the load command region

Inserts a load command at the given offset. will leave the object in an inconsistent state.

Parameters:

  • offset (Integer)

    the offset to insert at

  • lc (LoadCommands::LoadCommand)

    the load command to insert

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :repopulate (Boolean) — default: true

    whether or not to repopulate the instance fields

Raises:



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/macho/macho_file.rb', line 165

def insert_command(offset, lc, options = {})
  context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
  cmd_raw = lc.serialize(context)
  fileoff = offset + cmd_raw.bytesize

  raise OffsetInsertionError, offset if offset < header.class.bytesize || fileoff > low_fileoff

  new_sizeofcmds = sizeofcmds + cmd_raw.bytesize

  raise HeaderPadError, @filename if header.class.bytesize + new_sizeofcmds > low_fileoff

  # update Mach-O header fields to account for inserted load command
  update_ncmds(ncmds + 1)
  update_sizeofcmds(new_sizeofcmds)

  @raw_data.insert(offset, cmd_raw)
  @raw_data.slice!(header.class.bytesize + new_sizeofcmds, cmd_raw.bytesize)

  populate_fields if options.fetch(:repopulate, true)
end

#kext?Boolean

Returns whether or not the file is of type MH_KEXT_BUNDLE.

Returns:

  • (Boolean)

    whether or not the file is of type MH_KEXT_BUNDLE



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#linked_dylibsArray<String>

All shared libraries linked to the Mach-O.

Returns:

  • (Array<String>)

    an array of all shared libraries



336
337
338
339
340
341
342
# File 'lib/macho/macho_file.rb', line 336

def linked_dylibs
  # Some linkers produce multiple `LC_LOAD_DYLIB` load commands for the same
  # library, but at this point we're really only interested in a list of
  # unique libraries this Mach-O file links to, thus: `uniq`. (This is also
  # for consistency with `FatFile` that merges this list across all archs.)
  dylib_load_commands.map(&:name).map(&:to_s).uniq
end

#magicInteger

Returns the magic number.

Returns:

  • (Integer)

    the magic number



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#magic32?Boolean

Returns true if the Mach-O has 32-bit magic, false otherwise.

Returns:

  • (Boolean)

    true if the Mach-O has 32-bit magic, false otherwise



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#magic64?Boolean

Returns true if the Mach-O has 64-bit magic, false otherwise.

Returns:

  • (Boolean)

    true if the Mach-O has 64-bit magic, false otherwise



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#magic_stringString

Returns a string representation of the file's magic number.

Returns:

  • (String)

    a string representation of the file's magic number



123
124
125
# File 'lib/macho/macho_file.rb', line 123

def magic_string
  Headers::MH_MAGICS[magic]
end

#ncmdsInteger

Returns the number of load commands in the Mach-O.

Returns:

  • (Integer)

    the number of load commands in the Mach-O



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#object?Boolean

Returns whether or not the file is of type MH_OBJECT.

Returns:

  • (Boolean)

    whether or not the file is of type MH_OBJECT



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#populate_fieldsvoid

Note:

This method is public, but should (almost) never need to be called. The exception to this rule is when methods like #add_command and #delete_command have been called with repopulate = false.

This method returns an undefined value.

Populate the instance's fields with the raw Mach-O data.



247
248
249
250
# File 'lib/macho/macho_file.rb', line 247

def populate_fields
  @header = populate_mach_header
  @load_commands = populate_load_commands
end

#preload?Boolean

Returns whether or not the file is of type MH_PRELOAD.

Returns:

  • (Boolean)

    whether or not the file is of type MH_PRELOAD



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#replace_command(old_lc, new_lc) ⇒ void

Note:

This is public, but methods like #dylib_id= should be preferred.

This method returns an undefined value.

Replace a load command with another command in the Mach-O, preserving location.

Parameters:

Raises:

  • (HeaderPadError)

    if the new command exceeds the header pad buffer

See Also:



193
194
195
196
197
198
199
200
201
202
# File 'lib/macho/macho_file.rb', line 193

def replace_command(old_lc, new_lc)
  context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
  cmd_raw = new_lc.serialize(context)
  new_sizeofcmds = sizeofcmds + cmd_raw.bytesize - old_lc.cmdsize

  raise HeaderPadError, @filename if header.class.bytesize + new_sizeofcmds > low_fileoff

  delete_command(old_lc)
  insert_command(old_lc.view.offset, new_lc)
end

#rpathsArray<String>

All runtime paths searched by the dynamic linker for the Mach-O.

Returns:

  • (Array<String>)

    an array of all runtime paths



370
371
372
# File 'lib/macho/macho_file.rb', line 370

def rpaths
  command(:LC_RPATH).map(&:path).map(&:to_s)
end

#segment_alignmentInteger

Note:

This is not the same as #alignment!

Note:

See get_align and get_align_64 in cctools/misc/lipo.c

The segment alignment for the Mach-O. Guesses conservatively.

Returns:

  • (Integer)

    the alignment, as a power of 2



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/macho/macho_file.rb', line 273

def segment_alignment
  # special cases: 12 for x86/64/PPC/PP64, 14 for ARM/ARM64
  return 12 if %i[i386 x86_64 ppc ppc64].include?(cputype)
  return 14 if %i[arm arm64].include?(cputype)

  cur_align = Sections::MAX_SECT_ALIGN

  segments.each do |segment|
    if filetype == :object
      # start with the smallest alignment, and work our way up
      align = magic32? ? 2 : 3
      segment.sections.each do |section|
        align = section.align unless section.align <= align
      end
    else
      align = segment.guess_align
    end
    cur_align = align if align < cur_align
  end

  cur_align
end

#segmentsArray<LoadCommands::SegmentCommand>, Array<LoadCommands::SegmentCommand64>

All segment load commands in the Mach-O.

Returns:



261
262
263
264
265
266
267
# File 'lib/macho/macho_file.rb', line 261

def segments
  if magic32?
    command(:LC_SEGMENT)
  else
    command(:LC_SEGMENT_64)
  end
end

#serializeString

The file's raw Mach-O data.

Returns:

  • (String)

    the raw Mach-O data



79
80
81
# File 'lib/macho/macho_file.rb', line 79

def serialize
  @raw_data
end

#sizeofcmdsInteger

Returns the size of all load commands, in bytes, in the Mach-O.

Returns:

  • (Integer)

    the size of all load commands, in bytes, in the Mach-O



117
118
119
120
# File 'lib/macho/macho_file.rb', line 117

def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
:alignment

#to_hHash

Returns a hash representation of this MachO::MachOFile.

Returns:



469
470
471
472
473
474
# File 'lib/macho/macho_file.rb', line 469

def to_h
  {
    "header" => header.to_h,
    "load_commands" => load_commands.map(&:to_h),
  }
end

#write(filename) ⇒ void

This method returns an undefined value.

Write all Mach-O data to the given filename.

Parameters:

  • filename (String)

    the file to write to



454
455
456
# File 'lib/macho/macho_file.rb', line 454

def write(filename)
  File.binwrite(filename, @raw_data)
end

#write!void

Note:

Overwrites all data in the file!

This method returns an undefined value.

Write all Mach-O data to the file used to initialize the instance.

Raises:

  • (MachOError)

    if the instance was initialized without a file



462
463
464
465
466
# File 'lib/macho/macho_file.rb', line 462

def write!
  raise MachOError, "no initial file to write to" if @filename.nil?

  File.binwrite(@filename, @raw_data)
end