Assembly Flags
Trong bài này tôi sẽ giới thiệu về các cờ trong assembly (assembly flags).
Tất cả các cờ trong assembly là các giá trị 1 bit được lưu trữ trong một thanh ghi đặc biệt.
Có 4 cờ đặc biệt mà tôi đề cập ở đây:
- Z | ZF = Zero flag
- S | SF = Sign flag
- C | CF = Carry flag
- O | OF = Overflow flag
Những cờ trên sẽ thay đổi hoặc xét (1) giá trị khi thực hiện xong các lệnh toán học (bao gồm cả các lệnh logic), cũng như CMP
và các lệnh so sánh khác:
(“Được xét” trong bài viết này mang ý nghĩa là 1)
- Zero flag (ZF) được xét nếu kết quả của phép toán hoặc lệnh so sánh cuối cùng là 0. Nếu không nó sẽ được đặt lại.
- Sign flag (SF) được xét nếu kết quả của phép toán hoặc lệnh so sánh cuối là số âm. Nếu không nó sẽ được đặt lại. Đây cũng là cờ “negative flag”.
- Overflow flag (OF) sẽ được xét nếu kết quả không vừa với đích (destination) hay là bị tràn (overflow). Ví dụ: 0100 + 0100 = 1000 (cờ tràn được bật).
- Carry flag (CF) sẽ được xét khi hai số không dấu cộng, trừ với nhau và kết quả không vừa với đích (hoặc thanh ghi nó được lưu). Ví dụ: 1111 + 0001 = 0000 (cờ nhớ được bật – nhớ 1) hoặc 0000 – 0001 = 1111 (cờ nhớ được bật).
Các lệnh nhảy
Trong thực tế, tất cả các lệnh nhảy (JMP)
có điều kiện thực sự chỉ là “nhảy nếu cờ được đặt” hoặc “nhảy nếu cờ không được đặt” .
CMP A, B
-> Nó ảnh hưởng tới cờ như SUB A, B
nhưng nó không thực sự thực hiện phép trừ.
- JE X = Nhảy tới địa chỉ X nếu cờ Z được xét. Tương tự như JZ (nhảy nếu không).
- JNE X = Nhảy tới địa chỉ X nếu cờ Z bị xóa. Tương tự như JNZ (nhảy nếu không phải là 0).
- JGE X = Nhảy tới địa chỉ X nếu cờ S và cờ O có cùng giá trị. Tương tự như JNL (nhảy nếu không nhỏ hơn).
- JG X = Nhảy tới địa chỉ X nếu cờ S và cờ O có cùng giá trị và cờ Z không được đặt. Tương tự như JNLE (nhảy nếu không nhỏ hơn hoặc bằng).
- JL X = Nhảy tới địa chỉ X nếu cờ S và cờ O là các giá trị khác nhau. Giống như JNGE (nhảy nếu không lớn hơn hoặc bằng).
- JLE X = Nhảy tới địa chỉ X nếu cờ S và cờ O là các giá trị khác nhau hoặc nếu cờ Z được đặt. Tương tự như JNG (nhảy nếu không lớn hơn).
- JA X = Nhảy tới địa chỉ X nếu cờ Z và cờ C bị xóa. Tương tự như JNBE (nhảy nếu không thấp hơn hoặc bằng).
- JB X = Nhảy tới địa chỉ X nếu cờ C được thiết lập. Tương tự như JC (nhảy khi cờ nhớ bật) hoặc JNAE (nhảy nếu không cao hơn hoặc bằng).
- JBE X = Nhảy tới địa chỉ X nếu cờ C hoặc cờ Z được thiết lập. Tương tự như JNA (nhảy nếu không lớn hơn).
- JNB X = Nhảy tới địa chỉ X nếu cờ C bị xóa. Tương tự như JNC (nhảy nếu không nhớ) hoặc JAE (nhảy nếu lớn hơn hay bằng).
Ví dụ
MOV EAX, 244
CMP EAX, 244
JE 0x490A00
NOP
Bạn sẽ đặt câu hỏi là đoạn code trên sẽ nhảy tới địa chỉ 0x490A00
hay nó sẽ thực thi NOP
sau lệnh JMP 0x490A00
?
Tất nhiên nó sẽ nhảy đến 0x490A00. Vì EAX đang có giá trị là 244, và 244 thì sẽ bằng 244, lệnh JE sẽ được thực thi.
Tuy nhiên các cờ sẽ có giá trị như nào ?
- Lưu 244 vào EAX.
- Vì CMP EAX, 244 ảnh hưởng tới cờ như SUB EAX, 244 và kết quả có phép tính trên là 0.
- Bởi vì kết quả của phép tính bằng 0 nên cờ Z được xét.
- JE sẽ chỉ nhảy đến địa chỉ nếu cờ Z được xét, do đó lệnh nhảy được thực thi.
Máy tính không thực sự hiểu EAX bằng 244. Nó chỉ giả vờ trừ 244 cho EAX bằng lệnh CMP, và kết quả sẽ là 0 dẫn tới cờ Z được xét.
Ví dụ khác:
MOV EAX, FFFFFFFF
MOV ECX, 202
ADD EAX, ECX
JC 0x49F1DC
Ở ví dụ trên tôi đang cố gắng thực hiện nhảy có điều kiện mà không sử dụng CMP. Chuyện gì sẽ xảy ra ?
Tôi thực hiện phép toán CỘNG 202 với FFFFFFFF và lưu kết quả vào EAX. Cờ nhớ sẽ được xét vì kết quả của phép cộng quá lớn để lưu vào EAX, và nó chỉ tiếp tục thực hiện có giá trị là 201. Lệnh nhảy JC sẽ thực hiện vì cờ C đã được xét.
Tham khảo:
- https://www.cavestory.org/guides/csasm/guide/asm_flags.html