2010-07-14 20 views
21

Làm cách nào để sử dụng RIP Relative Addressing trong một chương trình lắp ráp Linux cho kiến ​​trúc AMD64? Tôi đang tìm một ví dụ đơn giản (một chương trình Hello world) sử dụng chế độ địa chỉ liên quan đến AMD64 RIP.Làm thế nào để sử dụng RIP Relative Addressing trong một chương trình lắp ráp 64 bit?

Ví dụ chương trình lắp ráp 64-bit sau sẽ làm việc với bình thường (địa chỉ tuyệt đối):

.text 
    .global _start 

_start: 
    mov $0xd, %rdx 

    mov $msg, %rsi 
    pushq $0x1 
    pop %rax 
    mov %rax, %rdi 
    syscall 

    xor %rdi, %rdi 
    pushq $0x3c 
    pop %rax 
    syscall 

.data 
msg: 
    .ascii "Hello world!\n" 

Tôi đoán rằng cùng một chương trình sử dụng RIP Relative Addressing sẽ là một cái gì đó như:

.text 
    .global _start 

_start: 
    mov $0xd, %rdx 

    mov msg(%rip), %rsi 
    pushq $0x1 
    pop %rax 
    mov %rax, %rdi 
    syscall 

    xor %rdi, %rdi 
    pushq $0x3c 
    pop %rax 
    syscall 

msg: 
    .ascii "Hello world!\n" 

Phiên bản bình thường chạy tốt khi được biên soạn với:

as -o hello.o hello.s && ld -s -o hello hello.o && ./hello 

Nhưng tôi không thể làm việc với phiên bản RIP.

Bất kỳ ý tưởng nào?

--- chỉnh sửa ----

Câu trả lời của Stephen Canon làm cho phiên bản RIP hoạt động.

Bây giờ khi tôi tháo rời thực thi của phiên bản RIP tôi nhận được:

objdump -d chào

0000000000400078 <.text>: 
    400078: 48 c7 c2 0d 00 00 00 mov $0xd,%rdx 
    40007f: 48 8d 35 10 00 00 00 lea 0x10(%rip),%rsi  # 0x400096 
    400086: 6a 01     pushq $0x1 
    400088: 58     pop %rax 
    400089: 48 89 c7    mov %rax,%rdi 
    40008c: 0f 05     syscall 
    40008e: 48 31 ff    xor %rdi,%rdi 
    400091: 6a 3c     pushq $0x3c 
    400093: 58     pop %rax 
    400094: 0f 05     syscall 
    400096: 48     rex.W 
    400097: 65     gs 
    400098: 6c     insb (%dx),%es:(%rdi) 
    400099: 6c     insb (%dx),%es:(%rdi) 
    40009a: 6f     outsl %ds:(%rsi),(%dx) 
    40009b: 20 77 6f    and %dh,0x6f(%rdi) 
    40009e: 72 6c     jb  0x40010c 
    4000a0: 64 21 0a    and %ecx,%fs:(%rdx) 

nào cho thấy những gì tôi đang cố gắng để hoàn thành: lea 0x10 (% rip),% rsi nạp địa chỉ 17 byte sau lệnh lea là địa chỉ 0x400096 nơi chuỗi Hello world có thể được tìm thấy và do đó dẫn đến mã độc lập vị trí.

+1

Tại sao 17 byte sau (0x10 là 16)? – fadedbee

+3

https://www.tortall.net/projects/yasm/manual/html/nasm-effaddr.html nói: 'RIP là thanh ghi chỉ dẫn con trỏ, có chứa địa chỉ của vị trí ngay lập tức theo hướng dẫn hiện tại' nhưng' Lệnh lea' dài 7 byte, không phải là một. – fadedbee

+0

Tại sao cặp 'push' /' pop' thay vì 'mov'? –

Trả lời

18

Tôi tin rằng bạn muốn tải địa chỉ của chuỗi của bạn vào %rsi; mã của bạn cố gắng tải một quadword từ địa chỉ đó thay vì chính địa chỉ đó. Bạn muốn:

lea msg(%rip), %rsi 

nếu tôi không nhầm. Tôi không có một hộp linux để kiểm tra trên, tuy nhiên.

+0

Vâng, nó hoạt động, cảm ơn bạn rất nhiều! – Erik

+0

@Erik: vui lòng trợ giúp. –

+4

nếu sử dụng thông điệp lea (% rsp),% rsi thay vì thư ngỏ (% rip),% rsi (hoặc bất kỳ đăng ký nào nhưng không rip) địa chỉ của chính nhãn mes được thêm vào không được bù trừ từ giá trị đăng ký hiện tại được cung cấp. ví dụ, nếu msg nằm trong địa chỉ 0x1FF thì sử dụng lệnh lea msg (% rsp),% rsi gây rsi = * (rsp + 0x1FF) không rsi = * ((rsp - 0x1FF) + rsp) vì bộ tách cho 0x10 (% rip) vì khoảng cách từ rip hiện tại và msg là 0x10 byts. nhưng tôi không thể tìm thấy trong các tài liệu có sự khác biệt trong tính toán giữa rip và các thanh ghi khác – user2808671

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