Chuỗi công cụ GCC sử dụng cú pháp lắp ráp AT & T theo mặc định, nhưng hỗ trợ cho cú pháp Intel có sẵn thông qua chỉ thị .intel_syntax
.Cách sử dụng hằng số địa chỉ trong cấu trúc nội tuyến GCC x86
Thêm vào đó, cả AT & T và Intel cú pháp có sẵn trong một và một phiên bản prefix
noprefix
, mà khác nhau về dù có hoặc không đòi hỏi tiền tố đăng ký tên với một sigil %
.
Tùy thuộc vào chỉ thị nào có mặt, định dạng cho hằng số địa chỉ thay đổi.
Hãy xem xét đoạn code C sau
*(int *)0xdeadbeef = 0x1234;
Sử dụng objdump -d
, chúng tôi thấy rằng nó được biên dịch để hướng dẫn lắp ráp sau
movl $0x1234,0xdeadbeef
Vì không có đăng ký tham gia, đây là cú pháp chính xác cho cả hai .att_syntax prefix
và .att_syntax noprefix
, nghĩa là. được nhúng trong mã C, chúng trông giống như thế này
__asm__(".att_syntax prefix");
__asm__("movl $0x1234,0xdeadbeef");
__asm__(".att_syntax noprefix");
__asm__("movl $0x1234,0xdeadbeef");
Bạn có thể tùy chọn bao quanh hằng số địa chỉ bằng dấu ngoặc đơn, ví dụ:
__asm__("movl $0x1234,(0xdeadbeef)");
cũng sẽ hoạt động.
Khi thêm một sigil để một hằng địa chỉ đơn giản, mã sẽ không copile
__asm__("movl $0x1234,$0xdeadbeef"); // won't compile
Khi xung quanh biểu thức này với ngoặc đơn, trình biên dịch sẽ phát ra sai mã mà không báo trước, tức là
__asm__("movl $0x1234,($0xdeadbeef)"); // doesn't warn, but doesn't work!
Điều này sẽ phát ra không chính xác hướng dẫn
movl $0x1234,0x0
Trong Intel m ode, hằng số địa chỉ phải được đặt trước bằng một thanh ghi phân đoạn cũng như kích thước toán hạng và cờ PTR
nếu có thể có sự mơ hồ. Trên máy tính của tôi (máy tính xách tay lõi kép Intel với Windows XP và các phiên bản MinGW và Cygwin GCC hiện tại), thanh ghi ds
được sử dụng theo mặc định.
Dấu ngoặc vuông xung quanh hằng số là tùy chọn. Hằng số địa chỉ cũng được nhận dạng đúng nếu thanh ghi phân đoạn bị bỏ qua, nhưng các dấu ngoặc có mặt. Tuy nhiên, việc bỏ qua thanh ghi sẽ phát ra cảnh báo trên hệ thống của tôi.
Ở chế độ prefix
, thanh ghi phân khúc phải được bắt đầu bằng %
, nhưng chỉ sử dụng dấu ngoặc đơn sẽ vẫn hoạt động. Đây là những cách khác nhau để tạo ra các hướng dẫn chính xác:
__asm__(".intel_syntax noprefix");
__asm__("mov DWORD PTR ds:0xdeadbeef,0x1234");
__asm__("mov DWORD PTR ds:[0xdeadbeef],0x1234");
__asm__("mov DWORD PTR [0xdeadbeef],0x1234"); // works, but warns!
__asm__(".intel_syntax prefix");
__asm__("mov DWORD PTR %ds:0xdeadbeef,0x1234");
__asm__("mov DWORD PTR %ds:[0xdeadbeef],0x1234");
__asm__("mov DWORD PTR [0xdeadbeef],0x1234"); // works, but warns!
Bỏ cả hai phân khúc đăng ký và dấu ngoặc sẽ thất bại để biên dịch
__asm__("mov DWORD PTR 0xdeadbeef,0x1234"); // won't compile
Tôi sẽ đánh dấu câu hỏi này như wiki cộng đồng, vì vậy nếu bạn có bất cứ điều gì hữu ích để thêm, cảm thấy tự do để làm như vậy.
Đó rõ ràng là không * chỉ * AS trong toolchain đây; (Các) phiên bản nào của gcc có liên quan? Bạn đã kiểm tra đầu ra của gcc -S để xác nhận rằng những gì đang được đưa vào GNU như là những gì bạn mong đợi? –
ok, đó là tôi đã làm rối tung - ít nhất là một phần; thay thế '($ 0xdeadbeaf)' với '0xdeadbeaf' dường như hoạt động; Tôi sẽ chỉnh sửa câu hỏi sau khi thử nghiệm ... – Christoph
@Charles: yes, 'gcc -S' mang lại kết quả mong đợi – Christoph