2012-03-21 25 views
8

Có cách nào để ghi đè lên các hàm có phạm vi tĩnh trong mô-đun đối tượng không?Có thể ghi đè các hàm tĩnh trong một mô-đun đối tượng (gcc, ld, x86, objcopy) không?

Nếu tôi bắt đầu với một cái gì đó như thế này, một mô-đun với toàn cầu biểu tượng "foo" là một chức năng mà các cuộc gọi biểu tượng địa phương "thanh", mà các cuộc gọi ký hiệu cục bộ "baz"

[[email protected] ~]$ cat foo.c 
#include <stdio.h> 
static void baz(void) 
{ 
    printf("baz\n"); 
} 

static void bar(void) 
{ 
    printf("bar\n"); 
    baz(); 
} 

void foo(void) 
{ 
    printf("foo\n"); 
    bar(); 
} 

[[email protected] ~]$ gcc -g -c foo.c 
[[email protected] ~]$ objdump -x foo.o | egrep 'foo|bar|baz' 
foo.o:  file format elf32-i386 
foo.o 
00000000 l df *ABS* 00000000 foo.c 
00000000 l  F .text 00000014 baz 
00000014 l  F .text 00000019 bar 
0000002d g  F .text 00000019 foo 

Nó có một toàn cầu, "foo" và hai địa phương "bar" và "baz".

Giả sử tôi muốn viết một số xét nghiệm đơn vị đó thực hiện thanh và baz, tôi có thể làm:

[[email protected] ~]$ cat barbaz 
bar 
baz 
[[email protected] ~]$ objcopy --globalize-symbols=barbaz foo.o foo2.o 
[[email protected] ~]$ objdump -x foo2.o | egrep 'foo|bar|baz' 
foo2.o:  file format elf32-i386 
foo2.o 
00000000 l df *ABS* 00000000 foo.c 
00000000 g  F .text 00000014 baz 
00000014 g  F .text 00000019 bar 
0000002d g  F .text 00000019 foo 
[[email protected] ~]$ 

Và bây giờ bar và baz là biểu tượng toàn cầu và truy cập từ bên ngoài module. Càng xa càng tốt.

Nhưng điều gì sẽ xảy ra nếu tôi muốn kết hợp chức năng của chính mình lên trên của "baz" và có "bar" gọi "baz" xen kẽ của tôi?

Có cách nào để làm điều đó không?

tùy chọn --wrap dường như không làm điều đó ...

[[email protected] ~]$ cat ibaz.c 
#include <stdio.h> 
extern void foo(); 
extern void bar(); 

void __wrap_baz() 
{ 
    printf("wrapped baz\n"); 
} 
int main(int argc, char *argv[]) 
{ 
    foo(); 
    baz(); 
} 

[[email protected] ~]$ gcc -o ibaz ibaz.c foo2.o -Xlinker --wrap -Xlinker baz 
[[email protected] ~]$ ./ibaz 
foo 
bar 
baz 
wrapped baz 
[[email protected] ~]$ 

Các baz gọi từ main() đã được bao bọc, nhưng thanh vẫn gọi là baz địa phương không phải là baz bọc.

Có cách nào để thực hiện thanh gọi cho bazơ được bao bọc không?

Thậm chí nếu nó yêu cầu sửa đổi mã đối tượng để tinker với địa chỉ của cuộc gọi hàm, nếu có thể được thực hiện theo cách tự động, có thể đủ tốt, nhưng trong trường hợp đó cần phải làm việc trên ít nhất i386 và x86_64.

- steve

+0

Tôi chưa sử dụng các ký hiệu yếu, nhưng chúng có vẻ giống như bazơ yếu của mô-đun ban đầu sẽ cho phép bạn thay thế bằng một mô-đun mới – x539

+0

Tôi tưởng tượng rằng nếu anh ấy cố gắng làm những việc như vậy, anh ấy không có quyền truy cập vào nguồn mã số –

+0

Tôi có quyền truy cập vào mã nguồn, nhưng tôi không muốn sửa đổi nguồn theo cách thông thường của kiểm tra đơn vị. Trên thực tế điều này là để thử nghiệm một mô-đun hạt nhân Linux. Thượng lưu, họ thường không thích bạn đặt những thay đổi trong nguồn chỉ dành cho những thứ mà không phải là hạt nhân, và cho khả năng tương thích vá, tôi không muốn gây rối với nguồn không cần thiết. – smcameron

Trả lời

3

Kể từ static là một lời hứa để trình biên dịch C là hàm hoặc biến là địa phương để các tập tin, trình biên dịch là miễn phí để loại bỏ mã đó nếu nó có thể nhận được kết quả tương tự mà không có nó.

Điều này có thể là nội tuyến trong cuộc gọi chức năng. Nó có thể có nghĩa là thay thế một biến bằng hằng số. Nếu mã nằm bên trong câu lệnh if luôn sai, hàm có thể không tồn tại trong kết quả được biên dịch.

Tất cả điều đó có nghĩa là bạn không thể chuyển hướng cuộc gọi đến chức năng đó một cách đáng tin cậy.

Nếu bạn biên dịch với tùy chọn -lto mới thậm chí còn tồi tệ hơn, bởi vì trình biên dịch được tự do sắp xếp lại, xóa hoặc nội tuyến tất cả mã trong toàn bộ dự án.

+0

Tôi nhận được xung quanh nội tuyến bằng cách biên dịch với -fno-inline. Không có chức năng nào mà tôi quan tâm, nó sẽ bị xóa hoàn toàn bởi trình biên dịch (nếu không thì tôi đã xóa chúng rồi). Có thể có một số trường hợp góc mà tôi không thể xử lý, nhưng không sao. Tôi quan tâm hơn đến trường hợp điển hình. Tôi không phản đối việc sửa đổi máy móc mã máy tại các địa điểm cuộc gọi để đạt được mục đích này, chỉ cần tìm ra cách để làm điều đó. – smcameron

1

Tôi nhận được email từ Ian Lance Taylor (tác giả của vàng, một mối liên kết thay thế cho ld):

Có cách nào để ghi đè lên chức năng với phạm vi tĩnh trong một mô-đun đối tượng? (Tôi đang sử dụng linux x86_64 và i386)

Không, không có.Đặc biệt, trình biên dịch có thể gọi nội dòng tới các hàm tĩnh và cũng có thể viết lại các hàm để sử dụng một quy ước gọi khác là (GCC thực hiện cả hai tối ưu hóa này). Vì vậy, có không có cách đáng tin cậy để ghi đè lên một chức năng tĩnh sau khi mã đã được biên dịch .

Nội tuyến có thể được xử lý, tôi nghĩ, bằng cách không cần thiết, nhưng việc thay đổi quy ước cuộc gọi có thể là quá nhiều.

Điều đó đang được nói, những kẻ DynamoRIO tuyên bố để có thể làm điều đó, nhưng tôi đã không xác minh nó: https://groups.google.com/forum/?fromgroups#!topic/dynamorio-users/xt8JTXBCZ74

0

Nếu bạn là okay với thay đổi mã máy thì bạn nên không có vấn đề sửa đổi mã nguồn .

Viết tập lệnh để tạo nguồn thử nghiệm đơn vị bằng máy từ nguồn thực. Perl thực hiện điều này rất tốt.

Các vấn đề liên quan