2012-01-01 19 views
13

Tôi đang cố gắng học viết ngôn ngữ lắp ráp cho hệ điều hành Mac 64 bit. Tôi không có vấn đề với 32 bit Mac OS và cả 32 bit và 64 bit Linux.Làm thế nào để viết ngôn ngữ lắp ráp chào chương trình thế giới cho 64 bit Mac OS X bằng printf?

Tuy nhiên, Mac OS 64 bit là khác nhau và tôi không thể tìm ra. Vì vậy tôi ở đây để nhờ giúp đỡ.

Tôi không gặp sự cố khi sử dụng lệnh gọi hệ thống để in. Tuy nhiên, tôi muốn tìm hiểu cách gọi hàm C bằng ngôn ngữ lắp ráp 64 bit của Mac OS.

hãy nhìn vào đoạn mã sau

.data 
_hello: 
    .asciz "Hello, world\n" 


.text 
.globl _main 
_main: 
    movq $0, %rax 
    movq _hello(%rip), %rdi 
    call _printf 

tôi sử dụng $ gcc -arch x86_64 hello.s

để lắp ráp và liên kết.

Nó tạo mã nhị phân. Tuy nhiên, tôi gặp lỗi phân đoạn khi chạy nó.

Tôi đã thử thêm "subq $ 8,% rsp" trước khi gọi _printf, vẫn giữ nguyên kết quả như trước.

Tôi đã làm gì sai?

Nhân tiện, có cách nào để gỡ lỗi mã này trên máy Mac không? Tôi đã thử thêm -ggdb hoặc -gstab hoặc -gDWARF và $ gdb ./a.out và không thể xem mã và đặt điểm ngắt.

+1

bài viết tốt về công ước gọi x86_64: http://nickdesaulniers.github.io/blog/2014/04/18/lets-write-some-x86-64/ –

+0

eax cho số lượng vararg: http://stackoverflow.com/questions/6212665, vấn đề căn chỉnh: http://stackoverflow.com/questions/10324333, http://stackoverflow.com/questions/14000351, câu hỏi chung: http://stackoverflow.com/questions/10857273 –

Trả lời

8

Bạn không nói chính xác vấn đề bạn đang gặp phải là gì, nhưng tôi đoán rằng bạn đang gặp sự cố tại thời điểm cuộc gọi đến printf. Điều này là do OS X (cả 32 và 64 bit) yêu cầu con trỏ ngăn xếp có liên kết 16 byte tại điểm của bất kỳ cuộc gọi hàm bên ngoài nào.

Con trỏ ngăn xếp được căn chỉnh 16 byte khi được gọi là _main; cuộc gọi đó đã đẩy địa chỉ trả về tám byte lên ngăn xếp, do đó ngăn xếp không được căn chỉnh 16 byte tại điểm gọi đến _printf. Trừ tám từ %rsp trước khi thực hiện cuộc gọi để căn chỉnh chính xác.


Vì vậy, tôi đã đi trước và sửa lỗi này cho bạn (không có ma thuật có liên quan, chỉ cần sử dụng gdb, break main, display/5i $pc, stepi, vv). Các vấn đề khác mà bạn đang gặp là ở đây:

movq _hello(%rip), %rdi 

này nạp tám byte đầu tiên của chuỗi của bạn vào %rdi, mà không phải là những gì bạn muốn ở tất cả (đặc biệt, tám byte đầu tiên của chuỗi của bạn không thể tạo thành một con trỏ hợp lệ thành chuỗi định dạng, dẫn đến sự cố trong printf). Thay vào đó, bạn muốn tải địa chỉ của chuỗi. Một phiên bản sửa lỗi của chương trình của bạn là:

.cstring 
_hello: .asciz "Hello, world\n" 

.text 
.globl _main 
_main: 
    sub $8, %rsp   // align rsp to 16B boundary 
    mov $0, %rax 
    lea _hello(%rip), %rdi // load address of format string 
    call _printf   // call printf 
    add $8, %rsp   // restore rsp 
    ret 
+0

Cảm ơn, Stephen. Tôi biết vấn đề liên kết chồng 16 byte. Tôi đã thêm subq $ 8,% rsp và vẫn nhận được lỗi phân đoạn ...Tôi nghi ngờ movq _hello (% rip),% rdi, tôi không chắc chắn điều này là đúng. Trên Linux tôi chỉ có thể sử dụng movq _hello,% rdi, nhưng mac sẽ phàn nàn rằng địa chỉ tuyệt đối không được hỗ trợ. –

+0

@AlfredZhong: đã cập nhật câu trả lời của tôi cho bạn. –

+0

Cảm ơn một lần nữa, Stephen! Nó hoạt động! Thật là một phép thuật! Tôi thực sự đã thử sử dụng leaq. Tuy nhiên, tôi đã không nhận ra ngay cả khi không đẩy bất kỳ tham số nào trên ngăn xếp, ngăn xếp vẫn phải được căn chỉnh 16 byte. Thật là một tình huống khó hiểu! –