2012-11-14 55 views
3

如在second answer for this question中可以看到的,使用該部分的名稱從本身內部獲取指向程序特定部分的指針非常簡單。使用libelf時,只需打開程序自己的文件,循環遍歷所有部分(其結構由Elf64_Shdr結構表示),當部分名稱與您想要的部分名稱匹配並停止使用存儲在Elf64_Shdr結構的sh_addr元素中的指針時停止。在這種情況下,獲取想要的指針非常簡單,因爲它是在ELF可執行文件中定義的。如何獲取指向動態庫(Linux ELF)特定部分的指針?

但是,想象一下,您有一個使用動態庫的程序,您需要獲取指向該動態庫的一部分的指針。由於其部分的地址是在運行時定義的,因此如何獲取指向動態庫部分的指針?

順便說一下,動態庫和主程序本身都有一個同名的段(這是我需要獲取指針的段)。因此,在這種情況下,這兩個具有相同名稱的段是否可以相鄰存儲在內存中,這樣我只需要獲得一個指向主文件段的指針(如我在第一段中所述)並添加一個偏移量到達動態庫部分?

+0

你可以得到的起始地址從/ proc/ /地圖,那麼你可以添加偏移。 – imreal

+0

@Nick好吧,但偏移使用什麼值?考慮到我可以用'libelf'獲得開始地址,是不是有更好的方法來做到這一點? – LuisABOL

+0

我甚至不確定是否有相同名稱的兩個部分(主文件和庫中的其中一個)相鄰存儲(它們當然不是)。所以我甚至不知道使用膠印是否會起作用...... – LuisABOL

回答

4

這是很簡單的,從自身內部

不一定得到一個指向的程序的特定部分。節表在實際運行時並不是真正需要的,並且可以完全剝離(只有段很重要,而不是段)。

由於其各部分的地址是在運行時定義的,因此如何獲取指向動態庫部分的指針?

該庫與主要可執行文件完全不同。主要區別在於,庫通常通過運行時加載器在地址0(主要可執行文件不是)和重新定位連接到某個其他常量偏移量。一旦你知道了偏移量,只需將它添加到開始部分(你可以從readelf -S foo.so或從libelf中找到),並且瞧:你已經得到了該部分的運行時地址。

那麼如何找到給定共享庫的重定位?

不雅的解決方案(Nick已經提出)是解析/proc/self/maps

更好的解決方案是使用(特定於glibc)dl_iterate_phdr。文檔here。你會想要使用dlpi_addr

+0

太棒了,男人!非常感謝你談論'dl_iterate_phdr'。我會盡量使用它,因爲它看起來正是我所需要的。但是,談到你的第一個觀察(「節表可以被完全剝離」),所以你的意思是'Elf64_Shdr'結構的'sh_addr'元素並不總是能夠成爲一個可以用來訪問節的指針,爲主文件? – LuisABOL

+0

@ LuisAntonioBotelhoO.Leite整個'.shstrtab'節可以被剝離。沒有它,你無法知道這些部分的名字是什麼(或者說,曾經是)。 –

0

這是很簡單的,這裏的一個例子:

#include <stdio.h> 

int i __attribute__((section("my_section"))) = 2; 
int j __attribute__((section("my_section"))) = 3; 
int k __attribute__((section("my_section"))) = 5; 

extern int __start_my_section; 
extern int __stop_my_section; 

int main(void) 
{ 
    int *p = &__start_my_section; 

    printf("%d\n", *p++); /* print k value */ 
    printf("%d\n", *p++); /* print j value */ 
    printf("%d\n", *p); /* print i value */ 

    return 0; 
}