2010-05-11 22 views
8

Trong khi xây dựng lắp ráp của tôi cho nền tảng x86 tôi gặp phải một số vấn đề với mã hóa các JMP hướng dẫn:Làm thế nào là một JMP tương đối (x86) thực hiện trong một Assembler?

OPCODE INSTRUCTION SIZE 
EB cb  JMP rel8  2 
E9 cw  JMP rel16 4 (because of 0x66 16-bit prefix) 
E9 cd  JMP rel32 5 
... 

(từ website lệnh x86 yêu thích của tôi, http://siyobik.info/index.php?module=x86&id=147)

Tất cả đều tương nhảy, trong đó kích thước của mỗi mã hóa (toán hạng + toán hạng) nằm trong cột thứ ba.

Thiết kế ban đầu của tôi (và do đó do lỗi này) đã dành khoảng không gian tối đa (5 byte) cho mỗi lệnh. Toán hạng chưa được biết, bởi vì đó là một bước nhảy đến một vị trí chưa biết. Vì vậy, tôi đã thực hiện một "viết lại" cơ chế, mà viết lại các toán hạng ở vị trí chính xác trong bộ nhớ, nếu vị trí của nhảy được biết đến, và điền phần còn lại với NOP s. Đây là một mối quan tâm hơi nghiêm trọng trong các vòng thắt chặt.

Bây giờ vấn đề của tôi là với các tình huống sau đây:

b: XXX 
c: JMP a 
e: XXX 
    ... 
    XXX 
d: JMP b 
a: XXX  (where XXX is any instruction, depending 
      on the to-be assembled program) 

Vấn đề là tôi muốn mã hóa nhỏ nhất có thể cho một hướng dẫn JMP (và không có NOP điền).

Tôi phải biết kích thước của lệnh tại c trước khi tôi có thể tính khoảng cách tương đối giữa ab cho toán hạng tại d. Điều tương tự cũng áp dụng cho số JMP tại c: cần biết kích thước của d trước khi có thể tính khoảng cách tương đối giữa ea.

Làm thế nào để các trình lắp ráp hiện có giải quyết được vấn đề này hoặc bạn sẽ làm như thế nào?

Đây là những gì tôi đang suy nghĩ mà giải quyết vấn đề:

Đầu tiên mã hóa tất cả các hướng dẫn để opcodes giữa JMP và đó là mục tiêu, nếu khu vực này chứa một opcode biến kích thước, sử dụng kích thước tối đa , ví dụ 5 cho số JMP. Sau đó mã hóa tương đối JMP thành mục tiêu của nó, bằng cách chọn kích thước mã hóa nhỏ nhất có thể (3, 4 hoặc 5) và tính khoảng cách. Nếu bất kỳ opcode có kích thước biến nào được mã hóa, hãy thay đổi tất cả các toán hạng tuyệt đối trước và tất cả các lệnh tương đối bỏ qua hướng dẫn được mã hóa này: chúng được mã hóa lại khi toán hạng của chúng thay đổi để chọn kích thước nhỏ nhất có thể. Phương pháp này được đảm bảo kết thúc, vì opcodes có kích thước biến chỉ có thể thu nhỏ (vì nó sử dụng kích thước tối đa của chúng).

Tôi tự hỏi, có lẽ đây là giải pháp được thiết kế quá mức, đó là lý do tôi đặt câu hỏi này.

+0

+1 cho liên kết tốt đẹp tài liệu asm –

Trả lời

1

Dưới đây là một cách tiếp cận tôi đã sử dụng mà có thể có vẻ không hiệu quả nhưng hóa ra lại không được cho hầu hết các mã thực tế cuộc sống (pseudo-code):

IP := 0; 
do 
{ 
    done = true; 
    while (IP < length) 
    { 
    if Instr[IP] is jump 
     if backwards 
     { Target known 
      Encode short/long as needed } 
     else 
     { Target unknown 
      if (!marked as needing long encoding) // see below 
      Encode short 
      Record location for fixup } 
    IP++; 
    } 
    foreach Fixup do 
    if Jump > short 
     Mark Jump location as requiring long encoding 
     PC := FixupLocation; // restart at instruction that needs size change 
     done = false; 
     break; // out of foreach fixup 
    else 
     encode jump 
} while (!done); 
+0

Gọn gàng! Mặc dù, nhưng bạn không thể biết điều đó, trình biên dịch và trình biên dịch của tôi chạy song song, vì vậy có thể mã được chèn vào giữa một mục tiêu và một bước nhảy tương đối ngược. Nhưng hai vòng lặp là một cách tiếp cận rất tốt, cảm ơn. (Ngoài ra PC = IP trong vòng lặp Fixup, tôi giả sử?) – Pindatjuh

+1

Oh yeah, xin lỗi - PC = IP. –

+0

Trên thực tế, tôi chỉ nhớ rằng có một biến chứng nhỏ với điều này: Khi bạn quay trở lại và thay đổi kích thước một bước nhảy, bạn cũng phải tính đến mọi bước nhảy ngắn về vị trí này mà bạn sắp mở rộng và giờ đây không còn nữa đạt được mục tiêu của họ. –

3

Trong lần vượt qua đầu tiên, bạn sẽ có xấp xỉ rất tốt với mã jmp để sử dụng bằng cách đếm số đếm bi quan cho tất cả các lệnh nhảy.

Khi vượt qua lần thứ hai, bạn có thể điền vào các bước nhảy với opcode bi quan được chọn. Rất ít bước nhảy có thể được viết lại để sử dụng một hoặc hai byte ít hơn, chỉ những bước nhảy rất gần với ngưỡng nhảy 8/16 bit hoặc 16/32 byte ban đầu.Vì các ứng cử viên đều nhảy nhiều byte, chúng ít có khả năng ở trong các tình huống vòng lặp quan trọng, do đó bạn có khả năng thấy rằng các đường chuyền tiếp tục cung cấp ít hoặc không có lợi ích nào cho một giải pháp vượt qua hai.

+0

Great câu trả lời : nhưng tại sao đường viền 128 byte (giữa 8/16 bit) ít có khả năng ở trong các tình huống vòng lặp quan trọng? Tôi có thể tưởng tượng một tình trạng vòng lặp quan trọng của chính xác 128 byte, mà sẽ chạy nhanh hơn so với sử dụng một bước nhảy 16-bit. Hoặc là tối ưu hóa sớm này? – Pindatjuh

+1

Vâng, ý tôi là một vòng lặp quan trọng là vòng lặp thử nghiệm và nhảy của vòng lặp là một phần quan trọng của mã vòng lặp. 128 byte là rất dài cho một vòng lặp như vậy, vòng lặp quan trọng nhất sẽ là một vài byte và bất kỳ nhảy ra khỏi vòng lặp có khả năng cũng nhỏ. –

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