2009-04-16 42 views
5

我已經使用windows主機上使用RVDS編譯器的* .o目標代碼文件(C源代碼)創建了共享庫(* .so)。如何從共享庫中導出符號

我這個共享對象鏈接與一個應用程序(使用Linux主機上ARM目標GCC),並獲得一個可執行文件,在運行產生分段錯誤。(我知道我必須調試它!)

代替創建共享庫,如果我使用相同的源文件創建一個靜態庫,然後鏈接到應用程序,然後執行該應用程序,它可以正常工作。

所以我的問題是: -

  1. 我是否需要使用一些結構,從而使得它工作正常出口(出口到應用功能)符號或其它任何標誌,明確地說,在我的源文件鏈接時與應用程序?需要什麼,我該怎麼做?

  2. 共享庫是如何工作的?也就是說,函數將被加載和運行的地址將在創建庫時給出庫中給出。應用程序(main())如何解析要執行庫函數的地址?

  3. 靜態庫是如何工作的,即靜態庫的情況下,這個地址是如何規定和解決的?

謝謝。

回答

11

這是它如何在Linux上工作:

1)不,你不需要做任何事情。但是,您可以使用gcc -fvisibility命令行參數限制導出變量,並使用visibility屬性顯式標記導出的條目。

2)該可執行文件將有一個它導入的所有函數的表格(這些都是具有默認可見性的所有函數)。加載器/鏈接器將在運行之前選擇一個地址加載庫並填充此表,這些函數的調用是間接調用。 (請注意,這也適用於共享對象)

3)靜態鏈接在鏈接時執行(即在編譯之後)。實際地址在組件中被替換,並且它們是直接調用。

注:有一種叫做PIC(位置無關代碼)的東西。 AFAIK,它處理對同一共享對象中的數據/函數的引用,因此鏈接器在加載庫時不需要覆蓋庫的一半代碼,而代碼不會對其進行任何絕對引用自己的數據。你可以嘗試嘗試一下。

0

你知道墜機原因嗎?

動態加載共享庫的一種可能性(例如,通過dlopen())是假設庫在沒有時加載了OK,然後嘗試通過空指針執行函數。

+0

@Jonathan:我沒有使用dlopen加載共享庫()調用。 – goldenmean 2009-05-25 11:53:20

3
  1. 你並不需要與gcc出口的符號,因爲它出口的所有符號默認;但是,RVDS可能會也可能不會這樣做。檢查您的RVDS編譯器文檔(嘗試將其配置爲'Relocatable ELF'輸出?)

  2. 在Linux共享庫必須是可重定位的,作爲基地址是在運行時確定的。生成與位置無關的代碼是理想的,因爲它減少移居庫所需要的工時量。如果你的庫沒有重定位它崩潰(換句話說,不從你的目標文件進行動態庫之前剝離重定位信息)。在選擇基地址並重新定位內部參考之後,符號在運行時解析爲地址。

  3. 對於靜態庫,所有符號,搬遷,和負載分配地址的情況發生在編譯時。

我唯一的猜測就是不知何故,編譯器發出的代碼在運行時不可重定位。對我來說,如何在不破壞靜態庫的情況下實現這個目標是個謎,儘管如此...

如果您直接從RVDS生成靜態庫和共享庫,那麼一個選擇是嘗試將該靜態庫到共享庫:

gcc -shared -o libfoo.so libfoo.a 

如果這會有所幫助,那麼RVDS的共享庫連接體(或它的配置)很可能打破。

相關問題