Skip to content

Commit

Permalink
macho/load_commands: support new macOS 15 dylib use command
Browse files Browse the repository at this point in the history
  • Loading branch information
Bo98 committed Jun 10, 2024
1 parent a3fc5a5 commit 9096066
Showing 1 changed file with 91 additions and 0 deletions.
91 changes: 91 additions & 0 deletions lib/macho/load_commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,20 @@ module LoadCommands
:SG_READ_ONLY => 0x10,
}.freeze

# association of dylib use flag symbols to values
# @api private
DYLIB_USE_FLAGS = {
:DYLIB_USE_WEAK_LINK => 0x1,
:DYLIB_USE_REEXPORT => 0x2,
:DYLIB_USE_UPWARD => 0x4,
:DYLIB_USE_DELAYED_INIT => 0x8,
}.freeze

# the marker used to denote a newer style dylib use command.
# the value is the timestamp 24 January 1984 18:12:16
# @api private
DYLIB_USE_MARKER = 0x1a741800

# The top-level Mach-O load command structure.
#
# This is the most generic load command -- only the type ID and size are
Expand Down Expand Up @@ -528,6 +542,41 @@ class DylibCommand < LoadCommand
# @return [Integer] the library's compatibility version number
field :compatibility_version, :uint32

# Instantiates a new DylibCommand or DylibUseCommand.
# macOS 15 and later use a new format for dylib commands (DylibUseCommand),
# which is determined based on a special timestamp and the name offset.
# @param view [MachO::MachOView] the load command's raw view
# @return [DylibCommand] the new dylib load command
# @api private
def self.new_from_bin(view)
dylib_command = super(view)

if dylib_command.instance_of?(DylibCommand) &&
dylib_command.timestamp == DYLIB_USE_MARKER &&
dylib_command.name.to_i == DylibUseCommand.bytesize
DylibUseCommand.new_from_bin(view)

Check warning on line 557 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L557

Added line #L557 was not covered by tests
else
dylib_command
end
end

# @example
# puts "this dylib is weakly loaded" if dylib_command.flag?(:DYLIB_USE_WEAK_LINK)
# @param flag [Symbol] a dylib use command flag symbol
# @return [Boolean] true if `flag` applies to this dylib command
def flag?(flag)
case cmd

Check warning on line 568 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L568

Added line #L568 was not covered by tests
when LOAD_COMMAND_CONSTANTS[:LC_LOAD_WEAK_DYLIB]
flag == :DYLIB_USE_WEAK_LINK

Check warning on line 570 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L570

Added line #L570 was not covered by tests
when LOAD_COMMAND_CONSTANTS[:LC_REEXPORT_DYLIB]
flag == :DYLIB_USE_REEXPORT

Check warning on line 572 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L572

Added line #L572 was not covered by tests
when LOAD_COMMAND_CONSTANTS[:LC_LOAD_UPWARD_DYLIB]
flag == :DYLIB_USE_UPWARD

Check warning on line 574 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L574

Added line #L574 was not covered by tests
else
false

Check warning on line 576 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L576

Added line #L576 was not covered by tests
end
end

# @param context [SerializationContext]
# the context
# @return [String] the serialized fields of the load command
Expand All @@ -553,6 +602,48 @@ def to_h
end
end

# The newer format of load command representing some aspect of shared libraries,
# depending on filetype. Corresponds to LC_LOAD_DYLIB or LC_LOAD_WEAK_DYLIB.
class DylibUseCommand < DylibCommand
# @return [Integer] any flags associated with this dylib use command
field :flags, :uint32

alias marker timestamp

# @example
# puts "this dylib is weakly loaded" if dylib_command.flag?(:DYLIB_USE_WEAK_LINK)
# @param flag [Symbol] a dylib use command flag symbol
# @return [Boolean] true if `flag` applies to this dylib command
def flag?(flag)
flag = DYLIB_USE_FLAGS[flag]

Check warning on line 618 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L618

Added line #L618 was not covered by tests

return false if flag.nil?

Check warning on line 620 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L620

Added line #L620 was not covered by tests

flags & flag == flag

Check warning on line 622 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L622

Added line #L622 was not covered by tests
end

# @param context [SerializationContext]
# the context
# @return [String] the serialized fields of the load command
# @api private
def serialize(context)
format = Utils.specialize_format(self.class.format, context.endianness)
string_payload, string_offsets = Utils.pack_strings(self.class.bytesize,

Check warning on line 631 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L630-L631

Added lines #L630 - L631 were not covered by tests
context.alignment,
:name => name.to_s)
cmdsize = self.class.bytesize + string_payload.bytesize
[cmd, cmdsize, string_offsets[:name], marker, current_version,

Check warning on line 635 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L634-L635

Added lines #L634 - L635 were not covered by tests
compatibility_version, flags].pack(format) + string_payload
end

# @return [Hash] a hash representation of this {DylibUseCommand}
def to_h
{
"flags" => flags,

Check warning on line 642 in lib/macho/load_commands.rb

View check run for this annotation

Codecov / codecov/patch

lib/macho/load_commands.rb#L642

Added line #L642 was not covered by tests
}.merge super
end
end

# A load command representing some aspect of the dynamic linker, depending
# on filetype. Corresponds to LC_ID_DYLINKER, LC_LOAD_DYLINKER, and
# LC_DYLD_ENVIRONMENT.
Expand Down

0 comments on commit 9096066

Please sign in to comment.