summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSutou Kouhei <kou@clear-code.com>2022-04-11 08:32:05 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2022-10-18 17:21:45 +0900
commite84ea4af695de307c4e66bf0d9aa445a1016a4af (patch)
treeebf9174f58a297859630b3ecab55d4a4bbd2b19a
parent93da67d46394007aa977c9345535c37878fd0db9 (diff)
[ruby/fiddle] Add support for linker script on Linux
GitHub: fix https://github.com/ruby/fiddle/pull/107 Reported by nicholas a. evans. Thanks!!! https://github.com/ruby/fiddle/commit/49ea1490df
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/6576
-rw-r--r--ext/fiddle/lib/fiddle.rb31
-rw-r--r--test/fiddle/test_fiddle.rb34
2 files changed, 64 insertions, 1 deletions
diff --git a/ext/fiddle/lib/fiddle.rb b/ext/fiddle/lib/fiddle.rb
index 09262c43ff..6137c487c6 100644
--- a/ext/fiddle/lib/fiddle.rb
+++ b/ext/fiddle/lib/fiddle.rb
@@ -58,7 +58,36 @@ module Fiddle
#
# 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
diff --git a/test/fiddle/test_fiddle.rb b/test/fiddle/test_fiddle.rb
index 8751d96920..2792897074 100644
--- a/test/fiddle/test_fiddle.rb
+++ b/test/fiddle/test_fiddle.rb
@@ -14,4 +14,38 @@ class TestFiddle < Fiddle::TestCase
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)