2013-05-14 21 views
8

Tôi đã thấy việc sử dụng gcc __section__ attribute (đặc biệt là trong hạt nhân Linux) để thu thập dữ liệu (thường là con trỏ hàm) vào các phần tùy chỉnh ELF. Làm thế nào là "công cụ" được đưa vào các phần tùy chỉnh được truy xuất và sử dụng?Làm thế nào để bạn có được địa chỉ bắt đầu và kết thúc của phần ELF tùy chỉnh trong C (gcc)?

+1

Có thể quan tâm: http://stackoverflow.com/questions/4152018/initialize-global-array-of-function-pointers-at-either-compile-time-or-run-time/4152185# 4152185 –

Trả lời

17

Miễn là tên phần dẫn đến tên biến C hợp lệ, gcc (ld, đúng hơn) tạo hai biến ma thuật: __start_SECTION__stop_SECTION. Những có thể được sử dụng để lấy các địa chỉ bắt đầu và kết thúc của một bộ phận, như vậy:

/** 
* Assuming you've tagged some stuff earlier with: 
* __attribute((__section__("my_custom_section"))) 
*/ 

struct thing *iter = &__start_my_custom_section; 

for (; iter < &__stop_my_custom_section; ++iter) { 
    /* do something with *iter */ 
} 

tôi không thể tìm thấy bất kỳ tài liệu chính thức cho tính năng này, chỉ có một mơ hồ vài mailing list tài liệu tham khảo. Nếu bạn biết tài liệu ở đâu, hãy viết nhận xét!

Nếu bạn đang sử dụng tập lệnh trình liên kết của riêng mình (như hạt nhân Linux), bạn sẽ phải tự thêm các biến ma thuật (xem vmlinux.lds.[Sh]this SO answer).

Xem here để biết ví dụ khác về cách sử dụng các phần tùy chỉnh ELF.

+0

Bạn cũng có thể sử dụng Objdump -d – Magn3s1um

+0

Lưu ý: Tôi đoán rằng vấn đề "tên biến C hợp lệ" có thể tránh được bằng cách sử dụng 'asm (" __ start_invalid.c.variable.name ")', nhưng hóa ra nó không hoạt động. – o11c

2

Linker có thể sử dụng những biểu tượng được xác định trong các mã, và có thể gán giá trị ban đầu của họ nếu bạn sử dụng tên chính xác trong kịch bản mối liên kết:

_smysection = .; 
*(.mysection) 
*(.mysection*) 
_emysection = .; 

Chỉ cần xác định một biến trong mã C:

const void * _smysection; 

Và sau đó bạn có thể truy cập đó dưới dạng biến thông thường.

u32 someVar = (u32)&_smysection; 
0

Vì vậy, câu trả lời ở trên, __start_SECTION__stop_SECTION sẽ làm việc, tuy nhiên đối với các chương trình để có thể sử dụng thông tin từ các mối liên kết bạn cần phải khai báo các biến như extern char* __start_SECTION. Thưởng thức!

extern char * __start_blobby; 

... 
printf("This section starts at %p\n", (unsigned int)&__start_blobby); 
... 
2

Thu thập các thông tin với nhau từ những câu trả lời khác nhau, đây là một ví dụ làm việc như thế nào để thu thập thông tin vào một phần tùy chỉnh mối liên kết và sau đó đọc các thông tin từ phần đó bằng cách sử dụng các biến kỳ diệu __start_SECTION__stop_SECTION trong chương trình C, trong đó SECTION là tên của phần trong bản đồ liên kết.

Các biến số __start_SECTION__stop_SECTION được tạo sẵn bởi trình liên kết vì vậy cần phải tạo tham chiếu rõ ràng cho các biến này khi chúng được sử dụng từ mã C.

Ngoài ra còn có một số vấn đề nếu sự liên kết được sử dụng bởi trình biên dịch để tính toán con trỏ/mảng bù đắp là khác với sự liên kết của các đối tượng được đóng gói trong từng phần của trình liên kết. Một giải pháp (được sử dụng trong ví dụ này) là lưu trữ chỉ một con trỏ tới dữ liệu trong phần trình liên kết.

#include <stdio.h> 

struct thing { 
    int val; 
    const char* str; 
    int another_val; 
}; 
struct thing data1 = {1, "one"}; 
struct thing data2 = {2, "two"}; 

/* The following two pointers will be placed in "my_custom_section". 
* Store pointers (instead of structs) in "my_custom_section" to ensure 
* matching alignment when accessed using iterator in main(). */ 
struct thing *p_one __attribute__((section("my_custom_section"))) = &data1; 
struct thing *p_two __attribute__((section("my_custom_section"))) = &data2; 

/* The linker automatically creates these symbols for "my_custom_section". */ 
extern struct thing *__start_my_custom_section; 
extern struct thing *__stop_my_custom_section; 

int main(void) { 
    struct thing **iter = &__start_my_custom_section; 
    for (; iter < &__stop_my_custom_section; ++iter) { 
     printf("Have thing %d: '%s'\n", (*iter)->val, (*iter)->str); 
    } 
    return 0; 
} 
Các vấn đề liên quan