2010-06-06 31 views
6

Tôi quyết định sẽ là vui vẻ để tìm hiểu lắp ráp x86 trong kỳ nghỉ hè. Vì vậy, tôi bắt đầu với một chương trình xin chào thế giới rất đơn giản, mượn các ví dụ miễn phí gcc -S có thể cho tôi. Tôi đã kết thúc với điều này:câu hỏi lắp ráp i386: tại sao tôi cần phải can thiệp với con trỏ ngăn xếp?

HELLO: 
    .ascii "Hello, world!\12\0" 
    .text 

.globl _main 
_main: 
    pushl %ebp  # 1. puts the base stack address on the stack 
    movl %esp, %ebp # 2. puts the base stack address in the stack address register 
    subl $20, %esp # 3. ??? 
    pushl $HELLO  # 4. push HELLO's address on the stack 
    call _puts  # 5. call puts 
    xorl %eax, %eax # 6. zero %eax, probably not necessary since we didn't do anything with it 
    leave    # 7. clean up 
    ret     # 8. return 
         # PROFIT! 

Nó biên dịch và thậm chí cả hoạt động! Và tôi nghĩ rằng tôi hiểu rõ nhất nhất của nó.

Mặc dù, phép thuật xảy ra ở bước 3. Tôi có xóa dòng này hay không, chương trình của tôi sẽ chết giữa cuộc gọi đến putsxor từ lỗi ngăn xếp không đúng. Và tôi có thay đổi $20 thành một giá trị khác không, nó cũng sẽ sụp đổ. Vì vậy, tôi đã đi đến kết luận rằng giá trị này là very quan trọng.

Vấn đề là, tôi không biết nó làm gì và tại sao cần thiết.

Có ai có thể giải thích cho tôi không? (Tôi đang sử dụng Mac OS, có bao giờ quan trọng không.)

Trả lời

3

Trên x86 OSX, ngăn xếp cần được căn chỉnh 16 byte cho các cuộc gọi hàm, xem ABI doc here. Vì vậy, giải thích là

 
push stack pointer (#1)   -4 
strange increment (#3)   -20 
push argument (#4)    -4 
call pushes return address (#5) -4 
total       -32 

Để kiểm tra, thay đổi dòng # 3 từ $ 20 đến $ 4, cũng hoạt động.

Ngoài ra, Ignacio Vazquez-Abrams chỉ ra, # 6 không bắt buộc. Các thanh ghi có chứa các phần còn lại của các phép tính trước đó, do đó nó phải được xóa một cách rõ ràng.

Gần đây tôi đã học được (vẫn đang học) lắp ráp. Để tiết kiệm cho bạn cú sốc, các quy ước gọi 64bit là MUCH khác nhau (các tham số được truyền trên thanh ghi). Tìm thấy this rất hữu ích cho việc lắp ráp 64bit.

3

Dạng chung của nhận xét phải là "Phân bổ không gian cho biến cục bộ". Tại sao thay đổi nó tùy tiện sẽ làm hỏng nó Tôi không chắc chắn. Tôi chỉ có thể nhìn thấy nó bị rơi nếu bạn giảm nó. Và bình luận thích hợp cho 6 là "Chuẩn bị trả về 0 từ hàm này".

+0

Vì vậy, giá trị trả lại được chuyển trong '% eax'? Tôi nghĩ rằng nó sẽ luôn luôn đi trên stack kể từ khi họ có khả năng có thể lớn hơn 32 bit. Và ngoài ra, tại sao tôi cần phân bổ 24 byte nếu tôi chỉ sử dụng 4 trong số đó? (__EDIT__ nó cũng hoạt động với 4. Vì vậy, tôi đoán ngăn xếp phải được căn chỉnh trên một ranh giới nhất định.) – zneak

+0

Âm thanh giống như nó đang gặp sự cố liên kết, không phải là tràn ngăn xếp. Các giá trị được trả về trong edx: eax, eax hoặc một lát của chúng hoặc một thanh ghi FPU. –

+0

Tôi khá chắc chắn rằng con trỏ ngăn xếp phải được căn chỉnh trên bội số của một DWORD (4 byte) trên x86 vì nó là 32-bit. – erjiang

1

Lưu ý rằng nếu bạn biên dịch với con trỏ -fomit-frame thì một số biểu tượng con trỏ %ebp sẽ biến mất. Con trỏ cơ sở là hữu ích để gỡ lỗi nhưng không thực sự cần thiết trên x86.

Ngoài ra, tôi khuyên bạn nên sử dụng cú pháp Intel, được hỗ trợ bởi tất cả các công cụ GCC/binutils. Tôi từng nghĩ rằng sự khác biệt giữa AT & T và Intel cú pháp chỉ là vấn đề của hương vị, nhưng sau đó một ngày tôi đi qua this example nơi AT & T mnemonic chỉ là hoàn toàn khác với Intel. Và vì tất cả các tài liệu chính thức x86 sử dụng cú pháp của Intel, nó có vẻ như là một cách tốt hơn để đi.

Hãy vui vẻ!

+0

Cảm ơn bạn rất nhiều. – zneak

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