簡體   English   中英

ld未定義引用,盡管找到了庫並導出了符號

[英]ld undefined reference, despite library found and symbols exported

現在已經48小時打架和關機了; 嘗試將動態庫與其依賴關系鏈接時,我仍然會收到未定義的引用錯誤 - 盡管存在所有導出,並且成功找到了庫。

場景:

  • libmemory(C ++) - 用extern "C"導出函數
  • libstring(C) - 導出函數,從libmemory導入

libmemory成功構建:

$ g++ -shared -fPIC -o ./builds/libmemory.so ...$(OBJECTS)...

libstring編譯成功,但無法鏈接:

$ gcc -shared -fPIC -o ./builds/libstring.so ...$(OBJECTS)... -L./builds -lmemory
./temp/libstring/string.o: In function `STR_duplicate':
string.c:(.text+0x1cb): undefined reference to `MEM_priv_alloc'
./temp/libstring/string.o: In function `STR_duplicate_replace':
string.c:(.text+0x2a0): undefined reference to `MEM_priv_free'
string.c:(.text+0x2bf): undefined reference to `MEM_priv_alloc'
/usr/bin/ld: ./builds/libstring.so: hidden symbol `MEM_priv_free' isn't defined
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status

驗證libmemory導出其符號,並使用-v到gcc找到庫本身:

...
attempt to open ./builds/libmemory.so succeeded
-lmemory (./builds/libmemory.so)
...

$ nm -gC ./builds/libmemory.so | grep MEM_
0000000000009178 T MEM_exit
0000000000009343 T MEM_init
00000000000093e9 T MEM_print_leaks
00000000000095be T MEM_priv_alloc
000000000000971d T MEM_priv_free
00000000000099c1 T MEM_priv_realloc
0000000000009d26 T MEM_set_callback_leak
0000000000009d3f T MEM_set_callback_noleak

$ objdump -T ./builds/libmemory.so | grep MEM_
0000000000009d3f g    DF .text  0000000000000019  Base        MEM_set_callback_noleak
00000000000093e9 g    DF .text  00000000000001d5  Base        MEM_print_leaks
0000000000009d26 g    DF .text  0000000000000019  Base        MEM_set_callback_leak
00000000000099c1 g    DF .text  0000000000000365  Base        MEM_priv_realloc
0000000000009343 g    DF .text  00000000000000a6  Base        MEM_init
00000000000095be g    DF .text  000000000000015f  Base        MEM_priv_alloc
000000000000971d g    DF .text  00000000000002a4  Base        MEM_priv_free
0000000000009178 g    DF .text  00000000000000a7  Base        MEM_exit

$ readelf -Ws ./builds/libmemory.so | grep MEM_
    49: 0000000000009d3f    25 FUNC    GLOBAL DEFAULT   11 MEM_set_callback_noleak
    95: 00000000000093e9   469 FUNC    GLOBAL DEFAULT   11 MEM_print_leaks
    99: 0000000000009d26    25 FUNC    GLOBAL DEFAULT   11 MEM_set_callback_leak
   118: 00000000000099c1   869 FUNC    GLOBAL DEFAULT   11 MEM_priv_realloc
   126: 0000000000009343   166 FUNC    GLOBAL DEFAULT   11 MEM_init
   145: 00000000000095be   351 FUNC    GLOBAL DEFAULT   11 MEM_priv_alloc
   192: 000000000000971d   676 FUNC    GLOBAL DEFAULT   11 MEM_priv_free
   272: 0000000000009178   167 FUNC    GLOBAL DEFAULT   11 MEM_exit
   103: 0000000000009343   166 FUNC    GLOBAL DEFAULT   11 MEM_init
   108: 0000000000009178   167 FUNC    GLOBAL DEFAULT   11 MEM_exit
   148: 0000000000009d3f    25 FUNC    GLOBAL DEFAULT   11 MEM_set_callback_noleak
   202: 00000000000095be   351 FUNC    GLOBAL DEFAULT   11 MEM_priv_alloc
   267: 000000000000971d   676 FUNC    GLOBAL DEFAULT   11 MEM_priv_free
   342: 0000000000009d26    25 FUNC    GLOBAL DEFAULT   11 MEM_set_callback_leak
   346: 00000000000099c1   869 FUNC    GLOBAL DEFAULT   11 MEM_priv_realloc
   366: 00000000000093e9   469 FUNC    GLOBAL DEFAULT   11 MEM_print_leaks

我有什么可怕的簡單嗎? 所有其他相關問題都有簡單的答案,如鏈接庫順序和使用的路徑 - 但我已經驗證它們已經到位並按預期工作。

修補 - -fvisibility導致沒有變化。

無論是使用clang還是gcc,都會產生相同的結果。

Linux 3.16.0-38-generic gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)

您應該將MEM_priv_alloc()函數標記為extern "C"或將函數體包裝為extern "C" { /* function implementation */ } (已經完成,因為我可以從描述中看到)。 並在標題中使用__cplusplusextern "C"組合

#ifdef __cplusplus
   #define EXTERNC extern "C"
#else
   #define EXTERNC
#endif

EXTERNC int MEM_priv_alloc (void);

還請仔細檢查MEM_priv_alloc原型是如何完成的。 例如, MEM_priv_alloc 應該是inline (不幸的是我不知道的這個物理學中,但是inline失敗對我來說為例)


以下是適用於我的簡化示例:

文件:

$ ls
main.c  Makefile  mem.cpp  mem.h  strings.c  strings.h

mem.cpp

#include <stdio.h>
#include "mem.h"
extern "C" int MEM_priv_alloc (void)
{
   return 0;
}

mem.h

#ifdef __cplusplus
   #define EXTERNC extern "C"
#else
   #define EXTERNC
#endif
EXTERNC int MEM_priv_alloc (void);

strings.c:

#include <stdio.h>
#include "mem.h"
int STR_duplicate_replace (void)
{
   MEM_priv_alloc();
}

strings.h:

int STR_duplicate_replace (void);

main.c中

#include <stdio.h>
#include "string.h"
int main (void)
{
   STR_duplicate_replace ();
   return 0;
}

Makefile文件:

prog: libmemory.so libstrings.so
        gcc -o $@ -L. -lmemory -lstrings main.c

libmemory.so: mem.cpp
        g++ -shared -fPIC -o $@ $^

libstrings.so: strings.c
        gcc -shared -fPIC -o $@ $^

和構建日志:

g++ -shared -fPIC -o libmemory.so mem.cpp
gcc -shared -fPIC -o libstrings.so strings.c
gcc -o prog -L. -lmemory -lstrings main.c

另請參閱C代碼wiki使用C ++庫的更多細節。 如何混合使用C和C ++

所以,我正在剝離合並的最后部分,並揭露了這個問題。

我的導入/導出模仿了這個: https//gcc.gnu.org/wiki/Visibility

我的等效實現最終看起來像這樣:

#     if GCC_IS_V4_OR_LATER
#             define DLLEXPORT        __attribute__((visibility("default")))
#             define DLLIMPORT        __attribute__((visibility("hidden")))
#     else
#             define DLLEXPORT
#             define DLLIMPORT
#     endif

DLLIMPORT(隱藏可見性)導致問題; 我用空白定義替換它,一切都好。 是的,我也有相同的鏗鏘聲,這就是為什么同樣失敗的原因。

我從中得到的結論是,C代碼只看到這些隱藏的符號,因此無論它多么努力,都無法導入它們,無論它們實際存在多少!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM