2013-08-25 58 views
5

Tôi cần gọi hàm bằng C chỉ bằng cách biết địa chỉ và không có thông tin trên nguyên mẫu đó (Tôi không thể truyền nó tới con trỏ hàm C).Gọi địa chỉ C làm chức năng không có mẫu thử

Thông tin tôi có về chức năng này là địa chỉ.

Tôi cũng biết các thông số tôi muốn chuyển cho nó (nhờ có con trỏ trống) và kích thước của mảng đối số (truy cập máng con trỏ trống).

Tôi cũng muốn tôn trọng quy ước gọi điện C. Đối với phiên bản x86, tôi khá nhiều biết làm thế nào để làm điều đó (phân bổ không gian trên ngăn xếp, sao chép các tham số để không gian đó và cuối cùng gọi hàm).

Vấn đề là với quy ước x64 (Linux hiện tại) trong đó thông số là được chuyển qua thanh ghi. Tôi không có ý tưởng về kích thước của mỗi tham số để điền đăng ký thích hợp, tôi chỉ biết kích thước của mảng tham số.

Ngoài ra, tôi không muốn phụ thuộc vào gcc vì vậy tôi không thể sử dụng __builtin_apply có vẻ như không chuẩn và cũng khá tối.

Tôi muốn viết đoạn mã riêng của mình để hỗ trợ nhiều trình biên dịch và cũng để tìm hiểu nội dung thú vị.

Vì vậy, về cơ bản, chức năng tôi muốn viết như nguyên mẫu giống như __builtin_apply đó là:

void *call_ptr(void (*fun)(), void *params, size_t size); 

Tôi cũng muốn đoạn code để viết nó trong C (nhờ asm inline) hoặc tinh khiết x64 asm .

Vì vậy, có cách nào để thực hiện việc này đúng cách và đối với quy ước gọi là không? Hoặc điều này là không thể với quy ước x64 mà không biết chính xác nguyên mẫu của hàm được gọi là ?

+4

Hãy xem [libffi] (http://sourceware.org/libffi/). – tangrs

+0

Điều này có thể là một thay thế tuyệt vời, nhưng vấn đề với libffi là nó cần phải biết loại của mỗi tham số và kiểu trả về của hàm. Tôi muốn tránh thu thập những thông tin này để tránh mất thời gian nếu có thể. Vì vậy, có thể với kiến ​​trúc x64? – Zerkan

+1

@ Zerkan không có, bạn cần các loại tham số, không có phép thuật nào có thể đặt các thông số trong sổ đăng ký thích hợp hoặc không gian ngăn xếp khi gọi một hàm mà không biết đối số – nos

Trả lời

0

Tôi nghĩ rằng, tất cả các quyết định của bạn sẽ không được hỗ trợ nhiều trình biên dịch, vì cơ chế của các đối số qua chức năng (thanh ghi, trật tự, ngăn xếp, bộ nhớ của họ) - đó là tính năng phụ thuộc biên dịch ...

+3

_ "Đó là tính năng phụ thuộc trình biên dịch" _. May mắn thay nó không phải là. Ít nhất là không nếu trình biên dịch tuân theo [ABI] (http://en.wikipedia.org/wiki/Application_binary_interface) của hệ điều hành đích. – Michael

+0

Có, tất nhiên, nó hỗ trợ một số giao diện cấp thấp bên ngoài. Nhưng, hỗ trợ ABI là tính năng phụ thuộc trình biên dịch quá =) Chỉ có một điều, bất kỳ trình biên dịch nào cũng phải hỗ trợ chính xác - Ngôn ngữ Standart –

2

Đặc biệt cho x64 gọi quy ước trên Linux này sẽ không làm việc cả.

Lý do là quy ước gọi điện rất phức tạp.

Một số ví dụ:

void funcA(float64 x); 
void funcB(int64 x); 

Trong hai trường hợp, những giá trị "x" được chuyển đến các chức năng khác nhau vì dấu chấm động và số nguyên được truyền cho các chức năng trong thanh ghi khác nhau.

void funcC(float64 x,int64 y); 
void funcD(int64 y,float64 x); 

Trong hai trường hợp này, đối số "x" và "y" theo thứ tự khác nhau. Tuy nhiên chúng được truyền cho hàm theo cùng một cách (cả hai hàm sử dụng cùng một thanh ghi cho "x" và cùng một thanh ghi cho "y").

Kết luận: Để tạo một hàm thực hiện những gì bạn muốn, bạn phải truyền một chuỗi chứa các kiểu đối số của mỗi đối số cho hàm assembly. Số lượng/kích thước của đối số chắc chắn là không đủ.Tuy nhiên nó chắc chắn sẽ có thể - miễn là nó chỉ hoạt động trên Linux.