2011-11-02 17 views
8

Tôi hiện đang sử dụng sơ đồ thay thế mã trong 32 bit, nơi mã được chuyển đến vị trí khác, đọc biến và một con trỏ lớp. Vì x86_64 không hỗ trợ địa chỉ tuyệt đối nên tôi gặp khó khăn khi lấy địa chỉ chính xác cho các biến ở vị trí mới của mã. Vấn đề một cách chi tiết là, vì địa chỉ liên quan rip địa chỉ con trỏ chỉ khác với thời gian biên dịch.Địa chỉ tuyệt đối để thay thế mã thời gian chạy trong x86_64

Vì vậy, có cách nào để sử dụng địa chỉ tuyệt đối trong x86_64 hoặc cách khác để lấy địa chỉ của các biến không chỉ dẫn con trỏ tương đối?

Giống như: leaq variable(%%rax), %%rbx cũng sẽ hữu ích. Tôi chỉ muốn không phụ thuộc vào con trỏ chỉ dẫn.

Trả lời

6

Hãy thử sử dụng mô hình mã lớn cho x86_64. Trong gcc, bạn có thể chọn số này với -mcmodel = lớn. Trình biên dịch sẽ sử dụng địa chỉ tuyệt đối 64 bit cho cả mã và dữ liệu.

Bạn cũng có thể thêm -fno-pic để không cho phép tạo mã độc lập vị trí.

Edit: Tôi xây dựng một ứng dụng thử nghiệm nhỏ với -mcmodel = lớn và nhị phân kết quả chứa các chuỗi như

400b81:  48 b9 f0 30 60 00 00 movabs $0x6030f0,%rcx 
400b88:  00 00 00 
400b8b:  49 b9 d0 09 40 00 00 movabs $0x4009d0,%r9 
400b92:  00 00 00 
400b95:  48 8b 39    mov (%rcx),%rdi 
400b98:  41 ff d1    callq *%r9 

mà là một tải trọng của một 64 bit tuyệt đối ngay lập tức (trong trường hợp này là một địa chỉ) theo sau là một cuộc gọi gián tiếp hoặc một tải gián tiếp. Trình tự hướng dẫn

moveabs variable, %rbx 
addq %rax, %rbx 

là tương đương với một "leaq offset64bit (% rax),% RBX" (mà không tồn tại), với một số tác dụng phụ như cờ thay đổi, vv

+0

-mcmodel = lớn nên là giải pháp. tôi phải điều tra tại sao trình biên dịch gcc osx không hỗ trợ nó – nux

+0

Có thể nó đã cũ. Các mô hình mã nhỏ (tiêu chuẩn) và trung bình đã được bổ sung sớm, mô hình lớn đến sau. – hirschhornsalz

+0

tôi cảm ơn bạn rất nhiều điều này có vẻ rất tốt và dứt khoát giải quyết vấn đề giải quyết vấn đề tuyệt đối – nux

2

Những gì bạn đang hỏi là có thể thực hiện được nhưng không dễ dàng.

Một cách để làm điều đó là bù đắp cho việc di chuyển mã trong hướng dẫn của nó. Bạn cần phải tìm tất cả các hướng dẫn sử dụng địa chỉ liên quan đến RIP (chúng có các byte ModRM là 05h, 0dh, 15h, 1dh, 25h, 2dh, 35h hoặc 3dh) và điều chỉnh trường disp32 của mình bằng số lượng di chuyển (di chuyển do đó bị giới hạn ở +/- 2GB trong không gian địa chỉ ảo, có thể không được đảm bảo do không gian địa chỉ 64 bit lớn hơn 4GB).

Bạn cũng có thể thay thế những hướng dẫn với các khoản tương đương của họ, nhiều khả năng thay thế tất cả các hướng dẫn ban đầu với nhiều hơn một, ví dụ:

; These replace the original instruction and occupy exactly as many bytes as the original instruction: 
    JMP Equivalent1 
    NOP 
    NOP 
Equivalent1End: 

; This is the code equivalent to the original instruction: 
Equivalent1: 
    Equivalent subinstruction 1 
    Equivalent subinstruction 2 
    ... 
    JMP Equivalent1End 

Cả hai phương pháp này sẽ cần ít nhất một số thói quen x86 tháo thô sơ.

Trước đây có thể yêu cầu sử dụng VirtualAlloc() trên Windows (hoặc một số tương đương trên Linux) để đảm bảo bộ nhớ chứa bản vá của mã gốc nằm trong khoảng +/- 2GB của mã ban đầu đó. Và phân bổ tại các địa chỉ cụ thể vẫn có thể thất bại.

Sau này sẽ yêu cầu nhiều hơn là chỉ tháo gỡ nguyên thủy, mà còn giải mã và tạo mã lệnh đầy đủ.

Có thể có các quirks khác để làm việc xung quanh.

Có thể tìm thấy ranh giới hướng dẫn bằng cách đặt cờ TF trong thanh ghi RFLAGS để làm cho CPU tạo ra lỗi ngắt single-step ở cuối mỗi lệnh thực hiện. Một trình xử lý ngoại lệ gỡ lỗi sẽ cần phải nắm bắt và ghi lại giá trị của RIP của lệnh tiếp theo. Tôi tin rằng điều này có thể được thực hiện bằng cách sử dụng Structured Exception Handling (SEH) trong Windows (không bao giờ thử với các ngắt lỗi), không chắc chắn về Linux. Để làm việc này bạn sẽ phải làm cho tất cả các mã thực thi, mọi lệnh.

Btw, có địa chỉ tuyệt đối ở chế độ 64 bit, xem, ví dụ: MOV đến/từ chỉ lệnh tích lũy với opcodes từ 0A0h đến 0A3h.

+0

cảm ơn cho câu trả lời . theo như tôi hiểu bạn, cách tiếp cận là tính toán lại giá trị địa chỉ cho các mov lúc chạy. Điều này có vẻ nặng nề cho chương trình vì vậy nếu đó là cách duy nhất tôi sẽ suy nghĩ về một thực hiện khác nhau – nux

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