背景
嘗試分析可執行檔案時,我試驗了分析器 Intel VTune,我了解到有一個 API 庫 (ITT) 提供了啟動/停止分析的實用程式。它的基本功能__itt_resume()和__itt_pause()。觸發我的是該庫是可選的,即如果不加載 ITT 的運行時庫,這些函式基本上是 noops。
可選圖書館?
我想知道(首先在Linux上)
一個行程是否在他啟動時或在運行時(即惰性初始化)呼叫每個符號或庫的第一個符號時檢查他正在鏈接的動態庫是否已加載?我認為在Windows上它是在啟動時因為
can't find XXX.dll訊息,但我不確定在 Linux 上。另外,對于這個例子,即使符號沒有在some_process.c.如何在Linux上實作這個?看了一下ITT的Github repo,在很多macro tricky中,感覺關鍵就在這里:
#define ITTNOTIFY_VOID(n) (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)
基本上它用函式指標呼叫包裝每個函式呼叫(如果不是NULL)。
- 如何以跨平臺方式(Windows、Mac、Linux)實作這一點?
我最終得到了一個看起來像此處鏈接的代碼的最小示例,但它無法正常作業。在鏈接版本中,my_api_hello_impl()未按應有的方式呼叫。此外,沒有崩潰檢查外部符號的值api_hello_ptr()此外,當庫未鏈接時,不會
my_api.c
#include "my_api.h"
#include <stdio.h>
void(*api_hello_ptr)();
void api_hello_impl()
{
printf("Hello\n");
}
__attribute__((constructor))
static void init()
{
printf("linked\n");
api_hello_ptr = api_hello_impl;
}
我的API.h
#pragma once
extern void(*api_hello_ptr)();
inline void api_hello() { if(api_hello_ptr) api_hello_ptr(); }
some_process.c
#include "my_api.h"
int main()
{
// NOOPS of not linked at runtime
api_hello();
}
生成檔案
# my_api is not linked to some_process
some_process: some_process.c my_api.h
$(CC) -o $@ $<
my_api.so: my_api.c my_api.h
$(CC) -shared -fPIC -o $@ $<
test_linked: some_process my_api.so
LD_PRELOAD="$(shell pwd)/my_api.so" ./some_process
test_unlinked: some_process my_api.so
./some_process
.PHONY: test_linked test_unlinked
輸出:
$ make test_linked
LD_PRELOAD="/tmp/tmp.EkrQbILrNg/my_api.so" ./some_process
linked
$ make test_unlinked
./some_process
uj5u.com熱心網友回復:
行程是否在啟動時檢查他正在鏈接的動態庫是否已加載
是的,它確實。如果鏈接了動態庫了一個動態庫,那么它是一個運行時要求,系統加載器將不會在沒有首先找到并加載庫的情況下開始執行程式。有延遲加載的機制,但這在 Linux 上并不常見,它們是手動完成的或使用自定義庫。默認情況下,所有動態鏈接的物件都需要在執行開始之前加載。
注意:我假設我們在這里討論的是 ELF 可執行檔案,因為我們在 Linux 上。
如何在 Linux 上實作這個?
您可以使用宏或包裝函式,加上libdl(與 鏈接-ldl)和dlopen() 來完成dlsym()。基本上,在每個包裝器中,您要做的第一件事是檢查庫是否已經加載,如果沒有,則加載它。然后,找到并呼叫所需的符號。
是這樣的:
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
static void *libfoo_handle = NULL;
static int (*libfoo_func_a)(int, int);
static void load_libfoo_if_needed(void) {
if (!libfoo_handle) {
// Without "/" in the path, this will look in all standard system
// dynamic library directories.
libfoo_handle = dlopen("libfoo.so", RTLD_LAZY | RTLD_GLOBAL);
if (!libfoo_handle) {
perror("failed to load libfoo.so");
_exit(1);
}
// Optionally use dlsym() here to initialize a set of global
// function pointers, so that you don't have to do it later.
void *tmp = dlsym(libfoo_handle, "func_a");
if (!tmp) {
perror("no symbol func_a in libfoo.so");
_exit(1);
}
*((void**)&libfoo_func_a) = tmp;
}
}
int wrapper_libfoo_func_a(int a, int b) {
load_libfoo_if_needed();
return libfoo_func_a(a, b);
}
// And so on for every function you need. You could use macros as well.
如何以跨平臺方式(Windows、Mac、Linux)實作這一點?
對于 macOS,您應該擁有dlopen()并且dlsym()就像在 Linux 中一樣。
不確定如何在Windows 上執行此操作,但我知道有LoadLibrary()不同的版本(例如one、two等),它們應該或多或少等同于dlopen()and GetProcAddress(),這應該等同于dlsym().
另請參閱:在 Linux 或 OSX 中動態加載庫?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/533946.html
標籤:CLinux动态库
