2012-02-01 44 views
6

Tôi đã gặp phải điều gì đó mà tôi không hiểu rõ. Có một nguyên mẫu hàm:Con trỏ chức năng với GCC, gán địa chỉ

typedef void (* TMain) (void); 

và một biến chức năng:

TMain myFunc = MyFunc; 
... 
myFunc(); 

này hoạt động tốt, tất nhiên. Tại sao nó không phải.

Từ tệp MAP tôi biết rằng "MyFunc" ở vị trí 0x20100. Và bây giờ điều buồn cười. Sau khi gán "myFunc = MyFunc;" biến "myFunc" không chứa giá trị 0x20100 nhưng thay vì 0x20101!

Vấn đề của tôi là, tôi cần gọi hàm mà tôi biết địa chỉ từ bảng. Vì vậy, tôi nghĩ tôi có thể làm điều đó như thế

myFunc = (TMain) myTable [ 5 ]; // that would be 0x20100 
myFunc();       // which produces a proper crash 

Tuy nhiên Nếu tôi làm

myFunc = (TMain) ((Int8 *) myTable [ 5 ] + 1); 
myFunc(); 

sau đó nó hoạt động.

Điều gì xảy ra ở đây? Tôi có luôn phải thêm một khoản bù trừ 1 hay ít nhiều là ngẫu nhiên không? Hoặc có cách nào tốt hơn (và hoạt động) để hoàn thành nhiệm vụ không?

Cảm ơn rất nhiều vì bất kỳ gợi ý nào. Walter

+2

Không chắc chắn, nhưng điều này có thể phụ thuộc vào kiến ​​trúc. Vì vậy, có thể muốn nói đó là kiến ​​trúc đích. – phimuemue

+1

Mảng 'myTable' thuộc loại' TMain [] '? Tôi đoán nó không phải là vì bạn đang đúc nó. –

+1

Một số câu hỏi dành cho bạn: Bạn đang sử dụng nền tảng nào (ARM, x86 ...)? Bạn đã bao giờ kiểm tra địa chỉ thực tế của hàm bằng trình gỡ rối chưa? Bạn có thể thấy cách trình biên dịch tạo ra cuộc gọi gián tiếp "myFunc()" không? –

Trả lời

3

Một số kiến ​​trúc CPU dự trữ các byte đầu tiên của hàm cho các mục đích cụ thể. VAXen có một mặt nạ đăng ký lưu ở đó. CDC Cyber ​​đặt địa chỉ trả lại ở đó. Một số sử dụng một số bit của "địa chỉ" để chỉ ra địa chỉ indirection (offhand tôi không thể nhớ cái nào, nhưng họ là từ những năm 1970).

Trừ khi bạn thực sự biết bạn đang làm gì, bạn không nên viết mã mà loại số học con trỏ đó. Chỉ định biến tên hàm và được thực hiện với nó: được đảm bảo hoạt động trên mọi triển khai C.

3

Đoán của tôi là bạn đang ở trên một mục tiêu ARM và bạn đã xây dựng chương trình của mình ở chế độ Ngón tay cái? (Thumb là mặc định trên ARM Ubuntu hoặc Linaro.)

Bit dưới cùng của địa chỉ của hàm cho CPU biết bộ lệnh nào cần giải thích hàm. 0 là chế độ ARM. 1 là chế độ Thumb. Vì vậy, tất cả các con trỏ chức năng chế độ Thumb sẽ là lẻ.

Kiến trúc khác cũng sử dụng thành ngữ này theo cách này hay cách khác. Thông thường nó an toàn để chỉ số không hai bit dưới cùng của một địa chỉ (làm cho nó 4-byte liên kết) và giả định rằng đó là vị trí thực sự của hàm.

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