2013-10-15 21 views
5

Tôi đang viết mã để tạm thời sử dụng ngăn xếp của riêng tôi để thử nghiệm. Điều này làm việc khi tôi sử dụng lắp ráp nội tuyến theo nghĩa đen. Tôi đã hardcoding các địa điểm biến như offsets off của ebp. Tuy nhiên, tôi muốn mã của tôi để làm việc mà không có haivng đến địa chỉ bộ nhớ mã cứng vào nó, vì vậy tôi đã nhìn vào GCC EXTENDED INLINE ASSEMBLY. Những gì tôi có là như sau:

volatile intptr_t new_stack_ptr = (intptr_t) MY_STACK_POINTER; 
volatile intptr_t old_stack_ptr = 0; 
asm __volatile__("movl %%esp, %0\n\t" 
     "movl %1, %%esp" 
     : "=r"(old_stack_ptr) /* output */ 
     : "r"(new_stack_ptr) /* input */ 
     ); 

Điểm này trước hết là lưu con trỏ ngăn xếp vào biến old_stack_ptr. Tiếp theo, con trỏ ngăn xếp (% esp) được ghi đè bằng địa chỉ tôi đã lưu trong new_stack_ptr.

Mặc dù vậy, tôi thấy rằng GCC đã lưu% esp vào old_stack_ptr, nhưng KHÔNG thay thế% esp bằng new_stack_ptr. Sau khi kiểm tra sâu hơn, tôi thấy nó thực sự mở rộng lắp ráp của tôi và thêm hướng dẫn riêng của nó, nó như sau:

mov -0x14(%ebp),%eax 
mov %esp,%eax 
mov %eax,%esp 
mov %eax,-0x18(%ebp) 

Tôi nghĩ GCC đang cố gắng giữ gìn% esp, bởi vì tôi không có nó một cách rõ ràng khai báo là một toán tử "đầu ra" ... Tôi có thể hoàn toàn sai với điều này ...

Tôi thực sự muốn sử dụng lắp ráp nội tuyến mở rộng để làm điều này, bởi vì nếu không, có vẻ như tôi phải "mã cứng" vị trí offsets của% ebp vào assembly, và tôi muốn sử dụng các tên biến như thế này ... đặc biệt là vì mã này cần phải làm việc trên một vài hệ thống khác nhau. cho phép tôi làm rõ y nói rằng vị trí biến ... nhưng tôi không hiểu tại sao nó đang làm những thứ phụ và không cho phép tôi ghi đè lên con trỏ ngăn xếp như trước, kể từ khi tôi bắt đầu sử dụng lắp ráp mở rộng, nó đã làm điều này.

Tôi đánh giá cao bất kỳ trợ giúp nào !!!

+0

Không chắc chắn nếu điều này có ích, nhưng có thể '-fomit-frame-pointer' (được bật bằng' -O1' trở lên) sẽ loại bỏ sự cần thiết phải lo lắng về '% ebp'. – DaoWen

+0

Các công cụ bổ sung có lẽ là có bởi vì bạn đang làm một debug (không tối ưu hóa) xây dựng và GCC hiện nó theo mặc định để bắt lỗi tiềm năng. Tìm kiếm "GCC Stack Frame Checks" để xem các tùy chọn GCC cung cấp. – Skizz

Trả lời

8

Được rồi vấn đề là gcc đang phân bổ đầu vào và đầu ra cho cùng một thanh ghi eax. Bạn muốn nói với gcc rằng bạn đang clobbering đầu ra trước khi sử dụng đầu vào, aka. "earlyclobber".

asm __volatile__("movl %%esp, %0\n\t" 
     "movl %1, %%esp" 
     : "=&r"(old_stack_ptr) /* output */ 
     : "r"(new_stack_ptr) /* input */ 
     ); 

Lưu ý rằng dấu hiệu & cho đầu ra. Điều này sẽ sửa mã của bạn.

Cập nhật: cách khác, bạn có thể buộc đầu vào và đầu ra được cùng một thanh ghi và sử dụng xchg, như vậy:

asm __volatile__("xchg %%esp, %0\n\t" 
     : "=r"(old_stack_ptr) /* output */ 
     : "0"(new_stack_ptr) /* input */ 
     ); 

Thông báo các "0" nói rằng "đặt này vào cùng một thanh ghi như là đối số 0 ".

+0

Cảm ơn bạn rất nhiều! Tôi chưa bao giờ nghe nói về clobber trước đây. Câu trả lời tuyệt vời. Tôi rất trân trọng điều này. Điều đó đã sửa nó. – Chad

+1

Tôi cho rằng bạn có thể sử dụng 'xchg' và sau đó ép buộc đầu vào và đầu ra nằm trong cùng một thanh ghi. – Jester

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