Nếu bạn muốn gọi một C/C++ chức năng từ lắp ráp nội tuyến, bạn có thể làm một cái gì đó như thế này:trực tiếp gọi điện bằng GCC của lắp ráp nội tuyến
void callee() {}
void caller()
{
asm("call *%0" : : "r"(callee));
}
GCC sau đó sẽ phát ra mã mà trông như thế này:
movl $callee, %eax
call *%eax
Điều này có thể có vấn đề vì cuộc gọi gián tiếp sẽ phá hủy đường dẫn trên các CPU cũ hơn.
Vì địa chỉ callee
cuối cùng là một hằng số, người ta có thể tưởng tượng rằng nó sẽ có thể sử dụng ràng buộc i
. Trích dẫn từ GCC trực tuyến docs:
`i'
An immediate integer operand (one with constant value) is allowed. This includes symbolic constants whose values will be known only at assembly time or later.
Nếu tôi cố gắng sử dụng nó như thế này:
asm("call %0" : : "i"(callee));
tôi nhận được lỗi sau từ lắp ráp:
Error: suffix or operands invalid for `call'
Điều này là do GCC phát ra mã
call $callee
Thay vì
call callee
Vì vậy, câu hỏi của tôi là liệu nó có thể làm cho sản lượng GCC đúng call
.
Bạn có chắc chắn cuộc gọi gián tiếp phá hủy đường dẫn không? Bạn đã chuẩn bị chưa? Sự hiểu biết của tôi là vào những ngày cũ trên x86 (trước i686), các cuộc gọi gián tiếp rất tệ (tôi nhớ chúng là chậm hơn 10-100 lần so với K6 của tôi), nhưng ngày nay cpus thông minh hơn và có thể xử lý chúng tốt . Vì vậy, làm một số thử nghiệm trước khi bạn nhảy đến kết luận! –
@R ..: Bạn nói đúng: nếu tôi đánh giá điều này trên một CPU thực sự, nó không tạo ra bất kỳ sự khác biệt nào. Tôi đang chạy mã của tôi trong qemu, tuy nhiên, và nó dường như tạo sự khác biệt ở đó (khoảng 20% chu kỳ/cuộc gọi). – Job
Sau đó, tôi sẽ chỉ gắn bó với cách bạn đang thực hiện nó, với cuộc gọi gián tiếp. Điều này sẽ cho phép gcc tạo mã đúng cho các thư viện/thực thi PIC/PIE mà không cần phải chèn các hacks đặc biệt để xử lý những thứ này. –