漲知識(shí)了,Linux的ld和ldd一起用,可以幫我們分析運(yùn)行時(shí)加載庫(kù)文件失敗的原因
很多時(shí)候,開(kāi)發(fā)人員/運(yùn)維人員需要處理軟件運(yùn)行時(shí)報(bào)錯(cuò)找不到依賴庫(kù)的問(wèn)題,除了可以通過(guò)strace、gdb等工具跟蹤啟動(dòng)加載的過(guò)程獲得依賴庫(kù)信息,還可以通過(guò)本文介紹的 ld + ldd 命令,幫助分析。
這里以分析 libmpi_usempif80.so 這個(gè)動(dòng)態(tài)庫(kù)文件,依賴哪些其他動(dòng)態(tài)庫(kù),作為問(wèn)題起因。
首先介紹 ld 命令如何幫我們分析mpi_usempif80 庫(kù)依賴其他哪些庫(kù)?mpi_usempif80 庫(kù)被加載時(shí),會(huì)從當(dāng)前系統(tǒng)的哪些路徑下搜索這些庫(kù)?
#ld -lmpi_usempif08 --verbose
GNU ld (GNU Binutils for Ubuntu) 2.38
Supported emulations:
elf_x86_64
elf32_x86_64
elf_i386
elf_iamcu
elf_l1om
elf_k1om
i386pep
i386pe
using internal linker script:
==================================================
/* Script for -z combreloc -z separate-code */
/* Copyright (C) 2014-2022 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib");
SECTIONS
{
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.relr.dyn : { *(.relr.dyn) }
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(SORT(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
/* Thread Local Storage sections */
.tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we do not
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1. */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions. */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2. */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2. */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions. */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3. */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF 5. */
.debug_addr 0 : { *(.debug_addr) }
.debug_line_str 0 : { *(.debug_line_str) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_names 0 : { *(.debug_names) }
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.debug_sup 0 : { *(.debug_sup) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}
==================================================
ld: mode elf_x86_64
attempt to open /usr/local/lib/x86_64-linux-gnu/libmpi_usempif08.so failed
attempt to open /usr/local/lib/x86_64-linux-gnu/libmpi_usempif08.a failed
attempt to open /lib/x86_64-linux-gnu/libmpi_usempif08.so succeeded
/lib/x86_64-linux-gnu/libmpi_usempif08.so
libmpi_mpifh.so.40 needed by /lib/x86_64-linux-gnu/libmpi_usempif08.so
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/mpi/fortran/mpif-h/.libs/libmpi_mpifh.so.40 failed
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/.libs/libmpi_mpifh.so.40 failed
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libmpi_mpifh.so.40 failed
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libmpi_mpifh.so.40 failed
attempt to open /usr/local/lib/libmpi_mpifh.so.40 failed
found libmpi_mpifh.so.40 at /usr/lib/x86_64-linux-gnu/libmpi_mpifh.so.40
libmpi.so.40 needed by /lib/x86_64-linux-gnu/libmpi_usempif08.so
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/mpi/fortran/mpif-h/.libs/libmpi.so.40 failed
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/.libs/libmpi.so.40 failed
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libmpi.so.40 failed
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libmpi.so.40 failed
attempt to open /usr/local/lib/libmpi.so.40 failed
found libmpi.so.40 at /usr/lib/x86_64-linux-gnu/libmpi.so.40
libc.so.6 needed by /lib/x86_64-linux-gnu/libmpi_usempif08.so
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/mpi/fortran/mpif-h/.libs/libc.so.6 failed
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/.libs/libc.so.6 failed
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libc.so.6 failed
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libc.so.6 failed
attempt to open /usr/local/lib/libc.so.6 failed
attempt to open /usr/lib/x86_64-linux-gnu/fortran/gfortran/libc.so.6 failed
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libc.so.6 failed
attempt to open /usr/local/lib/x86_64-linux-gnu/libc.so.6 failed
attempt to open /usr/local/lib/x86_64-linux-gnu/libc.so.6 failed
attempt to open /usr/lib/x86_64-linux-gnu64/libc.so.6 failed
attempt to open /usr/local/lib64/libc.so.6 failed
attempt to open /lib64/libc.so.6 failed
attempt to open /usr/lib64/libc.so.6 failed
attempt to open /usr/local/lib/libc.so.6 failed
attempt to open /lib/libc.so.6 failed
attempt to open /usr/lib/libc.so.6 failed
attempt to open /usr/x86_64-linux-gnu/lib64/libc.so.6 failed
attempt to open /usr/x86_64-linux-gnu/lib/libc.so.6 failed
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/mpi/fortran/mpif-h/.libs/libc.so.6 failed
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/.libs/libc.so.6 failed
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libc.so.6 failed
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libc.so.6 failed
attempt to open /usr/local/lib/libc.so.6 failed
found libc.so.6 at /usr/lib/x86_64-linux-gnu/libc.so.6
libopen-pal.so.40 needed by /usr/lib/x86_64-linux-gnu/libmpi_mpifh.so.40
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/.libs/libopen-pal.so.40 failed
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/opal/.libs/libopen-pal.so.40 failed
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libopen-pal.so.40 failed
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libopen-pal.so.40 failed
attempt to open /usr/local/lib/libopen-pal.so.40 failed
found libopen-pal.so.40 at /usr/lib/x86_64-linux-gnu/libopen-pal.so.40
libopen-rte.so.40 needed by /usr/lib/x86_64-linux-gnu/libmpi.so.40
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libopen-rte.so.40 failed
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libopen-rte.so.40 failed
attempt to open /usr/local/lib/libopen-rte.so.40 failed
found libopen-rte.so.40 at /usr/lib/x86_64-linux-gnu/libopen-rte.so.40
libm.so.6 needed by /usr/lib/x86_64-linux-gnu/libmpi.so.40
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libm.so.6 failed
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libm.so.6 failed
attempt to open /usr/local/lib/libm.so.6 failed
found libm.so.6 at /usr/lib/x86_64-linux-gnu/libm.so.6
libhwloc.so.15 needed by /usr/lib/x86_64-linux-gnu/libmpi.so.40
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libhwloc.so.15 failed
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libhwloc.so.15 failed
attempt to open /usr/local/lib/libhwloc.so.15 failed
found libhwloc.so.15 at /usr/lib/x86_64-linux-gnu/libhwloc.so.15
ld-linux-x86-64.so.2 needed by /usr/lib/x86_64-linux-gnu/libc.so.6
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/ld-linux-x86-64.so.2 failed
attempt to open /usr/local/lib/ld-linux-x86-64.so.2 failed
found ld-linux-x86-64.so.2 at /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
libevent_core-2.1.so.7 needed by /usr/lib/x86_64-linux-gnu/libopen-pal.so.40
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libevent_core-2.1.so.7 failed
attempt to open /usr/local/lib/libevent_core-2.1.so.7 failed
found libevent_core-2.1.so.7 at /usr/lib/x86_64-linux-gnu/libevent_core-2.1.so.7
libevent_pthreads-2.1.so.7 needed by /usr/lib/x86_64-linux-gnu/libopen-pal.so.40
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libevent_pthreads-2.1.so.7 failed
attempt to open /usr/local/lib/libevent_pthreads-2.1.so.7 failed
found libevent_pthreads-2.1.so.7 at /usr/lib/x86_64-linux-gnu/libevent_pthreads-2.1.so.7
libz.so.1 needed by /usr/lib/x86_64-linux-gnu/libopen-rte.so.40
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libz.so.1 failed
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libz.so.1 failed
attempt to open /usr/local/lib/libz.so.1 failed
found libz.so.1 at /usr/lib/x86_64-linux-gnu/libz.so.1
libudev.so.1 needed by /usr/lib/x86_64-linux-gnu/libhwloc.so.15
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libudev.so.1 failed
attempt to open /usr/local/lib/libudev.so.1 failed
found libudev.so.1 at /usr/lib/x86_64-linux-gnu/libudev.so.1
ld -lmpi_usempif08 --verbose | grep found
found libmpi_mpifh.so.40 at /usr/lib/x86_64-linux-gnu/libmpi_mpifh.so.40
found libmpi.so.40 at /usr/lib/x86_64-linux-gnu/libmpi.so.40
ld: warning: cannot find entry symbol _start; not setting start address
found libc.so.6 at /usr/lib/x86_64-linux-gnu/libc.so.6
found libopen-pal.so.40 at /usr/lib/x86_64-linux-gnu/libopen-pal.so.40
found libopen-rte.so.40 at /usr/lib/x86_64-linux-gnu/libopen-rte.so.40
found libm.so.6 at /usr/lib/x86_64-linux-gnu/libm.so.6
found libhwloc.so.15 at /usr/lib/x86_64-linux-gnu/libhwloc.so.15
found ld-linux-x86-64.so.2 at /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
found libevent_core-2.1.so.7 at /usr/lib/x86_64-linux-gnu/libevent_core-2.1.so.7
found libevent_pthreads-2.1.so.7 at /usr/lib/x86_64-linux-gnu/libevent_pthreads-2.1.so.7
found libz.so.1 at /usr/lib/x86_64-linux-gnu/libz.so.1
found libudev.so.1 at /usr/lib/x86_64-linux-gnu/libudev.so.1
上面這段信息很長(zhǎng),有很多有價(jià)值的信息,如果你只想看關(guān)鍵部分,那么我保留其中的關(guān)鍵內(nèi)容,來(lái)一個(gè)精華版的輸出信息:
#ld -lmpi_usempif08 --verbose
GNU ld (GNU Binutils for Ubuntu) 2.38
Supported emulations:
elf_x86_64
……
using internal linker script:
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start) # 運(yùn)行時(shí)可執(zhí)行文件從代碼段的 _start 位置開(kāi)始運(yùn)行。
# 運(yùn)行時(shí)需從哪些目錄找動(dòng)態(tài)庫(kù)文件
SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib");
# 二進(jìn)制文件有哪些的代碼段、數(shù)據(jù)段
SECTIONS
{
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
……
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
……
/* Thread Local Storage sections */
# 線程本地存儲(chǔ)區(qū)域
.tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
# 數(shù)據(jù)區(qū)
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
# BSS區(qū)
.bss :
{
……
}
……
}
# 下面是本文的重點(diǎn)關(guān)注部分
==================================================
# 文件1:逐個(gè)目錄匹配是否找到被依賴的libmpi_usempif08.so 庫(kù)文件
ld: mode elf_x86_64
attempt to open /usr/local/lib/x86_64-linux-gnu/libmpi_usempif08.so failed
attempt to open /usr/local/lib/x86_64-linux-gnu/libmpi_usempif08.a failed
attempt to open /lib/x86_64-linux-gnu/libmpi_usempif08.so succeeded
# 找到了 libmpi_usempif08.so 庫(kù)文件
# 文件2:逐個(gè)目錄匹配是否找到被依賴的 libmpi_mpifh.so 庫(kù)文件
libmpi_mpifh.so.40 needed by /lib/x86_64-linux-gnu/libmpi_usempif08.so
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/mpi/fortran/mpif-h/.libs/libmpi_mpifh.so.40 failed
attempt to open /build/openmpi-RCkqwI/openmpi-4.1.2/debian/build-gfortran/ompi/.libs/libmpi_mpifh.so.40 failed
attempt to open /usr/lib/x86_64-linux-gnu/openmpi/lib/libmpi_mpifh.so.40 failed
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libmpi_mpifh.so.40 failed
attempt to open /usr/local/lib/libmpi_mpifh.so.40 failed
found libmpi_mpifh.so.40 at /usr/lib/x86_64-linux-gnu/libmpi_mpifh.so.40
# 找到了 libmpi_mpifh.so 庫(kù)文件
# 找 libmpi.so.40
libmpi.so.40 needed by /lib/x86_64-linux-gnu/libmpi_usempif08.so
……
found libmpi.so.40 at /usr/lib/x86_64-linux-gnu/libmpi.so.40
# 找 libc.so.6
libc.so.6 needed by /lib/x86_64-linux-gnu/libmpi_usempif08.so
……
found libc.so.6 at /usr/lib/x86_64-linux-gnu/libc.so.6
# 找 libopen-pal.so.40
libopen-pal.so.40 needed by /usr/lib/x86_64-linux-gnu/libmpi_mpifh.so.40
……
found libopen-pal.so.40 at /usr/lib/x86_64-linux-gnu/libopen-pal.so.40
# 找 libopen-rte.so.40
libopen-rte.so.40 needed by /usr/lib/x86_64-linux-gnu/libmpi.so.40
……
found libopen-rte.so.40 at /usr/lib/x86_64-linux-gnu/libopen-rte.so.40
# 找 libm.so.6
libm.so.6 needed by /usr/lib/x86_64-linux-gnu/libmpi.so.40
……
found libm.so.6 at /usr/lib/x86_64-linux-gnu/libm.so.6
libhwloc.so.15 needed by /usr/lib/x86_64-linux-gnu/libmpi.so.40
# 找 libhwloc.so.15
……略
# 找 libudev.so.1
libudev.so.1 needed by /usr/lib/x86_64-linux-gnu/libhwloc.so.15
attempt to open /usr/lib/x86_64-linux-gnu/libfakeroot/libudev.so.1 failed
attempt to open /usr/local/lib/libudev.so.1 failed
found libudev.so.1 at /usr/lib/x86_64-linux-gnu/libudev.so.1
進(jìn)一步,我們可以用 grep 過(guò)濾只顯示 mpi_usempif08 實(shí)際找到的庫(kù)的信息:
#ld -lmpi_usempif08 --verbose | grep found
found libmpi_mpifh.so.40 at /usr/lib/x86_64-linux-gnu/libmpi_mpifh.so.40
found libmpi.so.40 at /usr/lib/x86_64-linux-gnu/libmpi.so.40
ld: warning: cannot find entry symbol _start; not setting start address
found libc.so.6 at /usr/lib/x86_64-linux-gnu/libc.so.6
found libopen-pal.so.40 at /usr/lib/x86_64-linux-gnu/libopen-pal.so.40
found libopen-rte.so.40 at /usr/lib/x86_64-linux-gnu/libopen-rte.so.40
found libm.so.6 at /usr/lib/x86_64-linux-gnu/libm.so.6
found libhwloc.so.15 at /usr/lib/x86_64-linux-gnu/libhwloc.so.15
found ld-linux-x86-64.so.2 at /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
found libevent_core-2.1.so.7 at /usr/lib/x86_64-linux-gnu/libevent_core-2.1.so.7
found libevent_pthreads-2.1.so.7 at /usr/lib/x86_64-linux-gnu/libevent_pthreads-2.1.so.7
found libz.so.1 at /usr/lib/x86_64-linux-gnu/libz.so.1
found libudev.so.1 at /usr/lib/x86_64-linux-gnu/libudev.so.1
而ldd 與 ld是不同的。ldd是分析linux的運(yùn)行庫(kù)的依賴關(guān)系、ld是可執(zhí)行文件鏈接器常用于C/C++/Fortran等語(yǔ)言代碼生成可執(zhí)行文件的鏈接階段。
我們看下 使用 ldd 對(duì)同一個(gè)動(dòng)態(tài)庫(kù)所依賴的其他庫(kù)的分析:
#ldd /usr/lib/x86_64-linux-gnu/libmpi_usempif08.so.40.30.0
linux-vdso.so.1 (0x00007ffd2f3fd000)
libmpi_mpifh.so.40 => /usr/lib/x86_64-linux-gnu/libmpi_mpifh.so.40 (0x00007f34366bf000)
libmpi.so.40 => /usr/lib/x86_64-linux-gnu/libmpi.so.40 (0x00007f3436588000)
libc.so.6 => /usr/lib/x86_64-linux-gnu/libc.so.6 (0x00007f3436200000)
libopen-pal.so.40 => /usr/lib/x86_64-linux-gnu/libopen-pal.so.40 (0x00007f34364d5000)
libopen-rte.so.40 => /usr/lib/x86_64-linux-gnu/libopen-rte.so.40 (0x00007f3436143000)
libm.so.6 => /usr/lib/x86_64-linux-gnu/libm.so.6 (0x00007f343605c000)
libhwloc.so.15 => /usr/lib/x86_64-linux-gnu/libhwloc.so.15 (0x00007f3436477000)
/lib64/ld-linux-x86-64.so.2 (0x00007f343677c000)
libevent_core-2.1.so.7 => /usr/lib/x86_64-linux-gnu/libevent_core-2.1.so.7 (0x00007f3436442000)
libevent_pthreads-2.1.so.7 => /usr/lib/x86_64-linux-gnu/libevent_pthreads-2.1.so.7 (0x00007f343643d000)
libz.so.1 => /usr/lib/x86_64-linux-gnu/libz.so.1 (0x00007f3436040000)
libudev.so.1 => /usr/lib/x86_64-linux-gnu/libudev.so.1 (0x00007f3436016000)
這里的順序與ld -lmpi_usempif08 --verbose | grep found 的結(jié)果是一致的。