rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.23k stars 12.7k forks source link

Rust program using Linux C library links but fails to run #89751

Open LukeMauldin opened 3 years ago

LukeMauldin commented 3 years ago

For reference see discussion: https://users.rust-lang.org/t/linux-executable-lazy-loading/65621/24

Summary: On Linux x64 using either Rust 1.55 or Rust 1.57 nightly (a8f2463c6 2021-10-09), I have a simple Rust program that compiles and links against C libraries provided by a software vendor. The Rust program fails to run with undefined symbol errors even though the LD_LIBRARY_PATH is setup correctly. I have built a similar C program which links and runs as expected. Initially it was assumed the problem was due to RELRO but I wrote a custom linker script that strips off the RELRO link options and the Rust binary still fails to run. See the linker commands and readelf outputs below.

Additional information: The RHEL 7.9 is being used for the Rust and C program compiles. The vendor libraries being linked against are pretty old and were originally built on Suse 10 SP2. The vendor has provided an updated set of libraries that were built on RHEL 7.4 and I verified the Rust program compiled, linked, and runs as expected against the newer vendor libraries. Unfortunately, I need to get Rust linking/running against the older version of the vendor libraries because that is the version of the application still in use by the business. I think the issue is somehow related to the age of the vendor libraries but both C and Go programs (using CGO) will link and run against the vendor libraries and so I think Rust should as well.

Rust linker command:

cc -m64 /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.13p9e1ntyogo9xsq.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.1iij31zcahtqtiv5.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.1l6169r8k8eut7l2.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.2gjar0q85zo53a76.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.2k238mae54tufgj9.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.2khfd30djo2j9kj2.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.30j9pt2j18mofsvb.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.3aliuipsukidwcp1.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.3hccpq6246r15ccj.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.3mblox8452khn7gt.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.3t4cjyhj779kk0qr.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.3zuhas95lhzq610q.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.45wlivfnv8f4n4m0.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.4d3znlnisojq460.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.4kfpl27e23y5yblb.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.4tsmg47mo9ot09rg.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.56udpy3ecn6gwk3v.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.5a3amov6yy7wfscc.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.5cf61klwqdixyzvj.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.5orcigdhwyefptr.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.9x7slzthbld3jn.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.cde9lw0m0vpja0a.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.gzsb73e5bh99x9g.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.lphb1hwcx9397qd.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.q46zvmgwxroxyjw.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.uov2smtu6r3uncy.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.y30a08oijsqtlo9.rcgu.o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91.1lyc4h18v76f6y14.rcgu.o -Wl,--as-needed -L /USERHOME/CODEDIR/target/debug/deps -L /LIBDIR -L /usr/lib/x86_64-linux-gnu -L /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib -lae -lbom -lepm -lfclasses -lform -ltcinit -ltc -ltccore -lbase_utils -lps -lpublication -lqry -lres -lsa -ltcsoaprojectmanagement -lcfilter -lstdc++ -Wl,--start-group -Wl,-Bstatic /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-008055cc7d873802.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-06f01ac2578bda94.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-f9a3c3274a1835e0.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-d4cbb754ee9f4daa.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-95c14e1c1e3ebcc4.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-d489f0ca872880cc.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-75f07df0b18fea39.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-0c35b278736219a2.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-e530649c9a06e3c6.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-6b148909d375a785.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-cd15fa647f4775d1.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-74be3a703f788ba2.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-8f2c5b445c28b2e3.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-8480e85e0be96197.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-ac23a75f6f42004e.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-557ba8776e04d182.rlib /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-4beb03d03503c439.rlib -Wl,--end-group /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-dd7db1bec6909f24.rlib -Wl,-Bdynamic -lgcc_s -lutil -lrt -lpthread -lm -ldl -lc -Wl,--eh-frame-hdr -Wl,-znoexecstack -L /USERHOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib -o /USERHOME/CODEDIR/target/debug/deps/tclogin-3aa5bdb40b601d91 -Wl,--gc-sections -nodefaultlibs -Wl,--unresolved-symbols=ignore-all -Wl,-znorelro -Wl,-zlazy

Custom linker script:

#!/bin/bash

declare -a FILTERARGS
for ITEM in "$@"
do
    # if [[ "$ITEM" != "-Wl,-znow" && "$ITEM" != "-Wl,-zrelro" ]]; then
    #    FILTERARGS+=("$ITEM")
    # fi
    case "$ITEM" in
    -Wl,-znow|-Wl,-zrelro)
        # do nothing
        ;;
    *)
       FILTERARGS+=("$ITEM")
        ;;
    esac
done

echo "invoking: cc ${FILTERARGS[@]}"
cc ${FILTERARGS[@]}

Rust readelf -d

0x000000000000000c (INIT)               0x405530
 0x000000000000000d (FINI)               0x435f40
 0x0000000000000019 (INIT_ARRAY)         0x643000
 0x000000000000001b (INIT_ARRAYSZ)       16 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x643010
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x400298
 0x0000000000000005 (STRTAB)             0x401a20
 0x0000000000000006 (SYMTAB)             0x4006b8
 0x000000000000000a (STRSZ)              9597 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x645c80
 0x0000000000000002 (PLTRELSZ)           120 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x4054b8
 0x0000000000000007 (RELA)               0x404240
 0x0000000000000008 (RELASZ)             4728 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x404140
 0x000000006fffffff (VERNEEDNUM)         6
 0x000000006ffffff0 (VERSYM)             0x403f9e
 0x0000000000000000 (NULL)               0x0

Rust readelf -l

Elf file type is EXEC (Executable file)
Entry point 0x407c18
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000042200 0x0000000000042200  R E    200000
  LOAD           0x0000000000043000 0x0000000000643000 0x0000000000643000
                 0x0000000000002d08 0x0000000000002ed0  RW     200000
  DYNAMIC        0x0000000000045390 0x0000000000645390 0x0000000000645390
                 0x00000000000002c0 0x00000000000002c0  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  TLS            0x0000000000043000 0x0000000000643000 0x0000000000643000
                 0x0000000000000000 0x0000000000000078  R      10
  GNU_EH_FRAME   0x000000000003afa4 0x000000000043afa4 0x000000000043afa4
                 0x0000000000001004 0x0000000000001004  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .debug_gdb_scripts .eh_frame_hdr .eh_frame .gcc_except_table
   03     .init_array .fini_array .jcr .data.rel.ro .dynamic .got .got.plt .data .bss
   04     .dynamic
   05     .note.ABI-tag .note.gnu.build-id
   06     .tbss
   07     .eh_frame_hdr
   08

C readelf -d

0x000000000000000c (INIT)               0x401220
 0x000000000000000d (FINI)               0x4016e4
 0x0000000000000019 (INIT_ARRAY)         0x602428
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x602430
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x400298
 0x0000000000000005 (STRTAB)             0x400520
 0x0000000000000006 (SYMTAB)             0x4002e0
 0x000000000000000a (STRSZ)              2777 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x603000
 0x0000000000000002 (PLTRELSZ)           264 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x401118
 0x0000000000000007 (RELA)               0x4010a0
 0x0000000000000008 (RELASZ)             120 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x401030
 0x000000006fffffff (VERNEEDNUM)         3
 0x000000006ffffff0 (VERSYM)             0x400ffa
 0x0000000000000000 (NULL)               0x0

C readelf -l

Elf file type is EXEC (Executable file)
Entry point 0x401300
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000001a78 0x0000000000001a78  R E    200000
  LOAD           0x0000000000002428 0x0000000000602428 0x0000000000602428
                 0x0000000000000c68 0x0000000000000c78  RW     200000
  DYNAMIC        0x0000000000002450 0x0000000000602450 0x0000000000602450
                 0x0000000000000ba0 0x0000000000000ba0  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x0000000000001878 0x0000000000401878 0x0000000000401878
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000002428 0x0000000000602428 0x0000000000602428
                 0x0000000000000bd8 0x0000000000000bd8  R      1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame .gcc_except_table
   03     .init_array .fini_array .jcr .data.rel.ro .dynamic .got .got.plt .data .bss
   04     .dynamic
   05     .note.ABI-tag .note.gnu.build-id
   06     .eh_frame_hdr
   07
   08     .init_array .fini_array .jcr .data.rel.ro .dynamic .got
LukeMauldin commented 3 years ago

Update - I modified the custom linker script to also strip out -Wl,--as-needed linker option and that allowed the Rust executable to run like the C executable. I think this issue should remain open because I would like Rust to support these options via configuration OOTB rather than requiring a custom linking script. Working linker script:

#!/bin/bash

declare -a FILTERARGS
for ITEM in "$@"
do
    case "$ITEM" in
    -Wl,-znow|-Wl,-zrelro|-Wl,--as-needed)
        # do nothing
        ;;
    *)
       FILTERARGS+=("$ITEM")
        ;;
    esac
done

echo "invoking: cc ${FILTERARGS[@]}"
cc ${FILTERARGS[@]}