Sử dụng mã hóa dạng ngắn trong trường hợp đặc biệt cho AL / AX / EAX và các dạng ngắn khác và các lệnh đơn byte
Các ví dụ giả định chế độ 32/64 bit, trong đó kích thước toán hạng mặc định là 32 bit. Một tiền tố kích thước toán hạng thay đổi hướng dẫn thành AX thay vì EAX (hoặc đảo ngược ở chế độ 16 bit).
inc/dec
một thanh ghi (khác 8 bit): inc eax
/ dec ebp
. (Không phải x86-64:0x4x
byte opcode được tái sử dụng làm tiền tố REX, vì vậyinc r/m32
là mã hóa duy nhất.)
8-bit inc bl
là 2 byte, bằng cách sử dụng inc r/m8
opcode + ModR / M operand mã hóa . Vì vậy, sử dụng inc ebx
để tăng bl
, nếu nó an toàn. (ví dụ: nếu bạn không cần kết quả ZF trong trường hợp các byte trên có thể khác không).
scasd
: e/rdi+=4
, yêu cầu các thanh ghi trỏ vào bộ nhớ có thể đọc được. Đôi khi hữu ích ngay cả khi bạn không quan tâm đến kết quả FLAGS (như cmp eax,[rdi]
/ rdi+=4
). Và ở chế độ 64 bit, scasb
có thể hoạt động dưới dạng 1 byteinc rdi
, nếu lodsb hoặc stosb không hữu ích.
xchg eax, r32
: đây là nơi 0x90 NOP đến từ : xchg eax,eax
. Ví dụ: sắp xếp lại 3 thanh ghi với hai xchg
hướng dẫn trong một vòng lặp cdq
/ cho GCD theo 8 byte trong đó hầu hết các hướng dẫn là byte đơn, bao gồm cả lạm dụng / thay vì /idiv
inc ecx
loop
test ecx,ecx
jnz
cdq
: đăng nhập mở rộng EAX vào EDX: EAX, tức là sao chép bit cao của EAX sang tất cả các bit của EDX. Để tạo số 0 với số không âm, hoặc lấy 0 / -1 để thêm / phụ hoặc mặt nạ với. Bài học lịch sử x86: cltq
so vớimovslq
, và cả AT & T so với Intel ghi nhớ cho điều này và các vấn đề liên quan cdqe
.
lodsb / d : thích mov eax, [rsi]
/ rsi += 4
không có cờ ghi chú. (Giả sử DF là rõ ràng, mà các quy ước gọi tiêu chuẩn yêu cầu khi nhập chức năng.) Ngoài ra stosb / d, đôi khi là scas, và hiếm khi hơn Mov / cmps.
push
/ pop reg
. ví dụ: ở chế độ 64 bit, push rsp
/ pop rdi
là 2 byte, nhưng mov rdi, rsp
cần tiền tố REX và là 3 byte.
xlatb
tồn tại, nhưng hiếm khi hữu ích. Một bảng tra cứu lớn là điều cần tránh. Tôi cũng chưa bao giờ tìm thấy việc sử dụng cho AAA / DAA hoặc các hướng dẫn đóng gói BCD hoặc 2-ASCII khác.
1 byte lahf
/ sahf
hiếm khi hữu ích. Bạn có thể lahf
/ and ah, 1
thay thế setc ah
, nhưng nó thường không hữu ích.
Và đối với CF cụ thể, sẽ có sbb eax,eax
0 / -1, hoặc thậm chí không có tài liệu nhưng được hỗ trợ phổ biến 1 byte salc
(đặt AL từ Carry) mà sbb al,al
không ảnh hưởng đến cờ. (Đã xóa trong x86-64). Tôi đã sử dụng SALC trong Thử thách đánh giá cao người dùng # 1: Dennis ♦ .
1 byte cmc
/ clc
/ stc
(flip ("bổ sung"), xóa hoặc đặt CF) hiếm khi hữu ích, mặc dù tôi đã tìm thấy cách sử dụng đểcmc
bổ sung độ chính xác mở rộng với các khối cơ sở 10 ^ 9. Để thiết lập / xóa CF vô điều kiện, thường sắp xếp để điều đó xảy ra như một phần của hướng dẫn khác, ví dụ: xor eax,eax
xóa CF cũng như EAX. Không có hướng dẫn tương đương cho các cờ điều kiện khác, chỉ DF (hướng chuỗi) và IF (ngắt). Cờ mang là đặc biệt cho rất nhiều hướng dẫn; ca làm việc đặt nó, adc al, 0
có thể thêm nó vào AL trong 2 byte và tôi đã đề cập trước đó là SALC không có giấy tờ.
std
/ cld
hiếm khi có vẻ đáng giá . Đặc biệt là trong mã 32 bit, tốt hơn là chỉ sử dụng dec
trên một con trỏ và mov
toán hạng nguồn hoặc bộ nhớ cho một lệnh ALU thay vì đặt DF so lodsb
/ stosb
đi xuống thay vì lên trên. Thông thường nếu bạn cần hướng xuống, bạn vẫn có một con trỏ khác đi lên, vì vậy bạn cần nhiều hơn một std
và cld
trong toàn bộ chức năng để sử dụng lods
/ stos
cho cả hai. Thay vào đó, chỉ cần sử dụng các hướng dẫn chuỗi cho hướng lên. (Các quy ước gọi tiêu chuẩn đảm bảo DF = 0 khi nhập chức năng, do đó bạn có thể cho rằng miễn phí mà không cần sử dụng cld
.)
Lịch sử 8086: tại sao các bảng mã này tồn tại
Trong nguyên bản 8086, AX là rất đặc biệt: hướng dẫn thích lodsb
/ stosb
, cbw
, mul
/div
và những người khác sử dụng nó ngầm. Tất nhiên đó vẫn là trường hợp; x86 hiện tại đã không giảm bất kỳ opcodes nào của 8086 (ít nhất là không phải bất kỳ trong số các tài liệu chính thức). Nhưng các CPU sau này đã thêm các hướng dẫn mới đưa ra các cách tốt hơn / hiệu quả hơn để thực hiện mọi việc mà không cần sao chép hoặc hoán đổi chúng sang AX trước. (Hoặc đến EAX ở chế độ 32 bit.)
ví dụ 8086 thiếu các bổ sung sau này như movsx
/movzx
để tải hoặc di chuyển + gia hạn đăng nhập hoặc 2 và 3 toán hạng imul cx, bx, 1234
không tạo ra kết quả nửa cao và không có bất kỳ toán hạng ngầm nào.
Ngoài ra, nút cổ chai chính của 8086 là tìm nạp lệnh, vì vậy tối ưu hóa kích thước mã rất quan trọng đối với hiệu suất trước đó . Nhà thiết kế ISA của 8086 (Stephen Morse) đã dành rất nhiều không gian mã hóa opcode cho các trường hợp đặc biệt cho AX / AL, bao gồm các opcode đích (E) AX / AL đặc biệt cho tất cả các hướng dẫn ALU src tức thời cơ bản , chỉ cần opcode + ngay lập tức không có byte ModR / M. 2 byte add/sub/and/or/xor/cmp/test/... AL,imm8
hoặc AX,imm16
hoặc (ở chế độ 32 bit) EAX,imm32
.
Nhưng không có trường hợp đặc biệt nào EAX,imm8
, vì vậy mã hóa ModR / M thông thường add eax,4
ngắn hơn.
Giả định là nếu bạn sẽ làm việc trên một số dữ liệu, bạn sẽ muốn nó trong AX / AL, vì vậy việc hoán đổi một thanh ghi với AX là điều bạn có thể muốn làm, thậm chí có thể thường xuyên hơn sao chép một đăng ký vào AX với mov
.
Mọi thứ về mã hóa lệnh 8086 đều hỗ trợ mô hình này, từ các hướng dẫn như lodsb/w
cho đến tất cả các mã hóa trường hợp đặc biệt để thực hiện với EAX cho đến việc sử dụng ngầm của nó ngay cả để nhân / chia.
Đừng mang đi; nó không tự động là một chiến thắng để hoán đổi mọi thứ thành EAX, đặc biệt nếu bạn cần sử dụng trực tiếp với các thanh ghi 32 bit thay vì 8 bit. Hoặc nếu bạn cần xen kẽ các hoạt động trên nhiều biến trong các thanh ghi cùng một lúc. Hoặc nếu bạn đang sử dụng hướng dẫn với 2 thanh ghi, thì không thể thực hiện được.
Nhưng hãy luôn ghi nhớ: tôi có đang làm bất cứ điều gì ngắn hơn trong EAX / AL không? Tôi có thể sắp xếp lại để tôi có cái này trong AL không, hoặc tôi hiện đang tận dụng lợi thế của AL tốt hơn với những gì tôi đã sử dụng nó cho.
Kết hợp các hoạt động 8 bit và 32 bit một cách tự do để tận dụng bất cứ khi nào an toàn để làm như vậy (bạn không cần thực hiện đăng ký đầy đủ hoặc bất cứ điều gì).
push 200; pop edx
- 3 byte để khởi tạo.