Skip to content

Commit

Permalink
[ruby/fiddle] Add support for linker script on Linux
Browse files Browse the repository at this point in the history
GitHub: fix ruby/fiddle#107

Reported by nicholas a. evans. Thanks!!!

ruby/fiddle@49ea1490df
  • Loading branch information
kou authored and nobu committed Oct 18, 2022
1 parent 93da67d commit e84ea4a
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 1 deletion.
31 changes: 30 additions & 1 deletion ext/fiddle/lib/fiddle.rb
Expand Up @@ -58,7 +58,36 @@ def self.last_error= error
#
# See Fiddle::Handle.new for more.
def dlopen library
Fiddle::Handle.new library
begin
Fiddle::Handle.new(library)
rescue DLError => error
case RUBY_PLATFORM
when /linux/
case error.message
when /\A(\/.+?): (?:invalid ELF header|file too short)/
# This may be a linker script:
# https://sourceware.org/binutils/docs/ld.html#Scripts
path = $1
else
raise
end
else
raise
end

File.open(path) do |input|
input.each_line do |line|
case line
when /\A\s*(?:INPUT|GROUP)\s*\(\s*([^\s,\)]+)/
# TODO: Should we support multiple files?
return dlopen($1)
end
end
end

# Not found
raise
end
end
module_function :dlopen

Expand Down
34 changes: 34 additions & 0 deletions test/fiddle/test_fiddle.rb
Expand Up @@ -14,4 +14,38 @@ def test_windows_constant
end
end

def test_dlopen_linker_script_input_linux
omit("This is only for Linux") unless RUBY_PLATFORM.match?("linux")
if Dir.glob("/usr/lib/*/libncurses.so").empty?
omit("libncurses.so is needed")
end
# libncurses.so uses INPUT() on Debian GNU/Linux
# $ cat /usr/lib/x86_64-linux-gnu/libncurses.so
# INPUT(libncurses.so.6 -ltinfo)
handle = Fiddle.dlopen("libncurses.so")
begin
assert_equal("libncurses.so",
File.basename(handle.file_name, ".*"))
ensure
handle.close
end
end

def test_dlopen_linker_script_group_linux
omit("This is only for Linux") unless RUBY_PLATFORM.match?("linux")
# libc.so uses GROUP() on Debian GNU/Linux
# $ cat /usr/lib/x86_64-linux-gnu/libc.so
# /* GNU ld script
# Use the shared library, but some functions are only in
# the static library, so try that secondarily. */
# OUTPUT_FORMAT(elf64-x86-64)
# GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib64/ld-linux-x86-64.so.2 ) )
handle = Fiddle.dlopen("libc.so")
begin
assert_equal("libc.so",
File.basename(handle.file_name, ".*"))
ensure
handle.close
end
end
end if defined?(Fiddle)

0 comments on commit e84ea4a

Please sign in to comment.