簡體   English   中英

Linux 在運行時迭代 ELF“部分”頭文件

[英]Linux Iterate over ELF "section" headers during runtime

簡短版本:可以在運行時檢查所有 ELF“節”標頭,並為每個加載的共享庫獲取每個“節”標頭的重定位地址。

長版:我試圖在用戶空間中實現與內核中存在的動態調試相同的機制(dyn_debug)。 每個 LOG 宏實例在程序__attribute__((section("__verbose")))中的特定“部分”中創建靜態變量的工作方式這迫使編譯器將變量放在“.data”部分而不是“__verbose”中部分。 以后可以通過變量__start___verbose、__stop___verbose訪問該段的起始和停止地址。 通過這種方式,一些中央例程可以查看所有已注冊的“日志”條目並按需更改屬性。 這適用於靜態鏈接的可執行文件,但是當使用共享庫時,有幾個“__verbose”部分(每個共享庫一個),一個在可執行文件本身中。 (當然,我使用 -fPIC 標志是為了包含在庫中)還與“-export-dynamic”鏈接的所有內容以確保導出所有符號。

每個共享庫和主可執行文件都有用於 init 的屬性(構造函數)方法。

我在 2 個案例中觀察到了兩種不同的行為。

case1:對於第一種情況,庫不是用 ldopen 加載的,而是由“libc 加載器”加載的

  1. 引用 __start___verbose 總是返回相同的地址(主可執行文件的地址),其中只存在“主”可執行日志條目。

  2. dlsym(RTLD_NEXT, __start___verbose),返回“下一個”可解析庫的符號地址,所以實際上我得到了所有地址。

案例 2:使用 ldopen 加載庫

  1. 引用 __start___verbose 總是返回相同的地址(主可執行文件的地址)
  2. dlsym(RTLD_NEXT, __start___verbose) 返回 NULL。
  3. dlsym(RTLD_DEFAULT, __start___verbose) 返回“主”進程表。
  4. dlsym(handle, __start___verbose) - 返回正確的段地址

問題:除了 4 之外,用 ldopen 打開的庫有什么方法可以獲取那個符號,因為 4 需要從“加載程序”中顯式調用

代碼:

/* Main" */ 
void func1()
{
    static int attribute__((section("__verbose"))) var  = 1;
}

/* Shared library */
void func2()
{
    static int attribute__((section("__verbose"))) var  = 2;
}

/* Both in main and shared library 
 * Prints same address !!! BAD !! */
void __attribute__((constructor)) initializer()
{
    struct int *iter;

    for (iter = __start___verbose; iter != __stop___verbose; ++iter) {
        printf("Value is %d", *iter)
    }
}



/* Works for libraries opened by libc runtime.
 * Does not work for libraries opened with LDOPEN*/
 void __attribute__((constructor)) initializer()
 {
    struct int *iter = ;

    for (iter = dlsym(RTLD_NEXT, "__start___verbose"); iter != __stop___verbose; ++iter) {
        printf("Value is %d", *iter)
    }
}



/* Snippet for main doing dynamic loading */

handle = ldopen('path', RTLD_NOW)
iter = dlsym(handle, "__start___verbose")
for (; iter != __stop___verbose; ++iter) {
    printf("Value is %d", *iter)
}

您不應該在運行時訪問節信息。 部分不應在運行時使用,並且可能會從可執行文件中刪除(剝離)。

我可能會使用自定義鏈接器腳本:

.__verbose:
{
  PROVIDE_HIDDEN (__verbose_start = .);
  *(.__verbose)
  PROVIDE_HIDDEN (__verbose_end = .);
}

這為該部分定義了 HIDDEN 符號,因此每個 ELF 文件都將具有自己的這些符號版本。

然后 ELF 文件中的構造函數(或其他一些代碼)可以使用它們:

struct foo*;
extern struct foo* __verbose_start __attribute__((visibility("hidden")));
extern struct foo* __verbose_stop __attribute__((visibility("hidden")));

void __attribute__((constructor)) initializer()
{
   initialize_logging(__verbose_start,__verbose_stop);  
}

暫無
暫無

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

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