Skip to content

Commit

Permalink
Add support for linker script on Linux
Browse files Browse the repository at this point in the history
GitHub: fix GH-107

Reported by nicholas a. evans. Thanks!!!
  • Loading branch information
kou committed Apr 10, 2022
1 parent 9a5a1da commit 49ea149
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 1 deletion.
31 changes: 30 additions & 1 deletion lib/fiddle.rb
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 49ea149

Please sign in to comment.