2016-12-15 14 views
5

Tôi đang sử dụng lắp ráp x86 với thư viện Irvine.Cách dễ nhất để xác định xem giá trị của một thanh ghi có bằng không hay không?

Cách dễ nhất để kiểm tra xem giá trị sổ đăng ký có bằng không hay không?

Tôi đã sử dụng lệnh cmp nhưng tôi đang tìm kiếm cách thay thế. Đây là mã của tôi sử dụng lệnh cmp và đăng ký là ebx

cmp ebx,0 
    je equ1 
    mov ebx,0 
    jmp cont 
equ1: 
    mov ebx,1 
    jmp cont 
cont: 
    exit 

này "booleanizes" một giá trị, tạo ra một 0 hoặc 1 như int ebx = !!ebx sẽ trong C.

+4

Bạn đang sử dụng ít nhất 80386 hướng dẫn ('ebx' không tồn tại trên 8086). Ngoài ra, câu trả lời phụ thuộc vào hướng dẫn trước mã này, sự hiện diện của giá trị bằng không có thể sắp xếp "rò rỉ" theo các hướng dẫn trước đó, tiết kiệm cho bạn nhiều hơn ở bài kiểm tra, nếu không thành ngữ thường là 'test ebx, ebx' để đặt ZF. Sau đó, để biến ZF thành giá trị 0/1 trong ebx là một câu chuyện khác, nơi 'test' đó có thể không phải là một phần của giải pháp tối ưu. Hãy quyết định, cho dù bạn muốn xác định nếu đăng ký là số không, hoặc nếu bạn muốn thiết lập một số đăng ký để 0/1 theo nó. # 'mov ebx, 0' =' xor ebx, ebx' khi bạn có thể tiêu diệt cờ. – Ped7g

+0

Để minh họa quan điểm của tôi (tầm quan trọng của chi tiết), hãy nói lệnh sửa đổi cuối cùng (cờ và ebx) trước điều này là 'neg ebx'. Sau đó, 'sbb ebx, ebx' sẽ đặt' ebx' thành -1 khi 'ebx' bằng 0 và 0 cho giá trị khác 0 (tiếp theo là' neg ebx' sẽ biến nó thành 0/1 cách làm việc ban đầu của bạn). – Ped7g

+0

không hoạt động với tôi. –

Trả lời

11

Có thể là "dễ nhất" hoặc đơn giản nhất, "không quan tâm đến chi tiết" trả lời cách xác định là:

; here ebx is some value, flags are set to anything 
    test ebx,ebx ; CF=0, ZF=0/1 according to ebx 
    jz  whereToJumpWhenZero 
    ; "non-zero ebx" will go here 

    ; Or you can use the inverted "jnz" jump to take 
    ; a branch when value was not zero instead of "jz". 

Có một lý do chi tiết về các cờ đang được đặt, v.v. :)

Làm thế nào để thiết lập một số đăng ký khác (Tôi sẽ chọn eax) 1 khi ebx là zero, và đến 0 khi ebx là (cách không phá hoại cho ebx chính nó) khác không:

xor eax,eax ; eax = 0 (upper 24 bits needed to complete "al" later) 
    test ebx,ebx ; test ebx, if it is zero (ZF=0/1) 
    setz al  ; al = 1/0 when ZF=1/0 (eax = 1/0 too) 

hoặc làm thế nào để chuyển đổi ebx mình thành 1/0 khi ebx là zero/non-zero:

neg ebx  ; ZF=1/0 for zero/non-zero, CF=not(ZF) 
    sbb ebx,ebx ; ebx = 0/-1 for CF=0/1 
    inc ebx  ; 1 when ebx was 0 at start, 0 otherwise 

hoặc làm thế nào để chuyển đổi ebx mình thành 1/0 khi 012.là zero/khác không, biến thể khác (nhanh hơn trên "P6" để lõi "Haswell"):

test ebx,ebx ; ZF=1/0 for zero/non-zero ebx 
    setz bl  ; bl = 1/0 by ZF (SETcc can target only 8b r/m) 
    movzx ebx,bl ; ebx = bl extended to 32 bits by zeroes 

vv, vv ... Nó phụ thuộc những gì xảy ra trước khi thử nghiệm của bạn, và cũng là những gì bạn thực sự muốn là đầu ra của thử nghiệm, có nhiều cách cách khác nhau (tối ưu cho các tình huống khác nhau và tối ưu cho các CPU mục tiêu khác nhau).


tôi sẽ thêm vài tình huống hơn rất phổ biến ... Một phản loop xuống đếm từ N đến zero, để lần N vòng:

mov ebx,5 ; loop 5 times 
exampleLoop: 
    ; ... doing something, preserving ebx 
    dec ebx 
    jnz exampleLoop ; loop 5 times till ebx is zero 

Làm thế nào để xử lý 5 yếu tố của word (16b) mảng (truy cập chúng trong mảng [0], mảng [1], ...thứ tự):

mov ebx,-5 
    lea esi,[array+5*2] 
exampleLoop: 
    mov ax,[esi+ebx*2] ; load value from array[i] 
    ; process it ... and preserve esi and ebx 
    inc ebx 
    jnz exampleLoop ; loop 5 times till ebx is zero 

Một ví dụ nữa, tôi bằng cách nào đó như thế này rất nhiều:

Làm thế nào để thiết lập mục tiêu đăng ký (eax trong ví dụ) để ~ 0 (-1)/0 khi ebx là zero/khác không và bạn đã có giá trị 1 trong một số đăng ký (ecx trong ví dụ):

; ecx = 1, ebx = some value 
    cmp ebx,ecx ; cmp ebx,1 => CF=1/0 for ebx zero/non-zero 
    sbb eax,eax ; eax = -1 (~0)/0 for CF=1/0 ; ebx/ecx intact 

Các -1 có thể trông như thực tế là 1 (cho mục đích lập chỉ mục s ít nhất), nhưng -1 hoạt động cũng như bitmask đầy đủ cho hoạt động hơn nữa and/xor/or, vì vậy đôi khi nó là thuận tiện hơn.

+0

Cảm ơn nó hoạt động chính xác :) tôi đánh giá cao sự giúp đỡ của bạn. –

+2

Đối với cùng một trường hợp đăng ký mà không sử dụng bất kỳ regs phụ: 'kiểm tra ebx, ebx' /' setz bl'/'movzx ebx, bl' nên hiệu quả hơn trên P6 để Haswell (SBB là 2c độ trễ/2 uop). 'neg/sbb/inc' hiệu quả hơn trên Pentium4 (slow setcc), và tôi nghĩ chúng ngang bằng với Broadwell và sau đó, và trên AMD (tất cả độ trễ 1c), và có kích thước mã nhỏ hơn (đặc biệt là trong 32-bit)). –

+1

test/setz/movzx là những gì gcc6.2 '-mtune = haswell' làm gì nếu bạn cho nó một tình huống mà nó muốn làm điều đó tại chỗ: https://godbolt.org/g/076BSI. Clang zeros một thanh ghi riêng biệt và sau đó sử dụng một mov. –

-3

Bạn có thể sử dụng:

or ebx, 0 ;This does nothing, just triggers the zero flag if ebx is zero 
jnz notZero 
or ebx, 1 ;ebx was zero, then ebx is 1 
notZero: 
+3

Downvoting khi bạn đi thẳng cho 'hoặc ebx, 0', ngay cả khi tôi đã đăng trong bình luận thành ngữ phổ biến là' kiểm tra ebx, ebx'. Bạn có thể có ít nhất sử dụng 'hoặc ebx, ebx' để tránh' 0' ngay lập tức, nhưng 'test' vẫn tốt hơn, vì nó được sử dụng rộng rãi bởi trình biên dịch C/C++, vì vậy CPU có thể tối ưu hóa thêm cho điều đó, trong khi 'hoặc' có thể được coi là phép toán số học thông thường. – Ped7g

+1

Vâng, tôi đã thấy câu trả lời của bạn sau khi tôi đăng bài của tôi, đã học được điều gì đó! Cảm ơn! – LeCalore

+3

@ Ped7g: Tìm hiểu thêm về lý do tại sao 'hoặc' là một lựa chọn không tốt cho việc này: http://stackoverflow.com/a/33724806/224132. Tóm tắt: Bên cạnh kích thước mã rõ ràng, 'kiểm tra ebx, ebx' có thể kết hợp macro với một JCC, và nó không viết EBX, giới thiệu thêm chu kỳ trễ vào chuỗi phụ thuộc cho điều tiếp theo để đọc EBX. Vì vậy, có, CPU làm "có tối ưu hóa thêm" cho TEST/JCC so với OR/JCC, và OR chỉ được xử lý giống như bất kỳ OR nào khác. –

2

Sử dụng cờ, Luke
Bạn kiểm tra xem đăng ký bằng không bằng cách kiểm tra cờ số không.
Nếu sổ đăng ký nhận được giá trị của nó bằng một số thao tác ảnh hưởng đến cờ (hoặc, cụ thể hơn, cờ số không) thì bạn không phải làm gì cả, vì cờ zero sẽ phản ánh giá trị được lưu trong thanh ghi đó.

Chỉ kiểm tra nếu cần
Nếu bạn không thể đảm bảo rằng cờ đã được đặt, bạn sẽ phải sử dụng thao tác kiểm tra.
Các hoạt động này có hai hương vị: phá hoại và không phá hủy.

Bạn có thể thấy một danh sách các hướng dẫn và cờ nó làm thay đổi tại địa chỉ: http://ref.x86asm.net -Xem thêm cụ thể, tại địa chỉ: http://ref.x86asm.net/coder32-abc.html

Các movlea hướng dẫn không bao giờ thay đổi cờ và do đó cần được giúp đỡ. Hầu hết các hướng dẫn khác đặt ít nhất một cờ.

Đừng tạo ra phụ thuộc sai
Nếu bạn cần phải kiểm tra một thanh ghi cho không, nhưng không muốn để thay đổi giá trị của nó, bạn sử dụng các hướng dẫn test.
Bạn không nên sử dụng lệnh or hoặc and để kiểm tra sổ đăng ký, vì CPU có thể không biết rằng or/and có thể được sử dụng không phá hủy và không thể áp dụng tối ưu hóa nhất định. Thuật ngữ kỹ thuật cho điều này là 'phụ thuộc sai'. Thanh ghi cần ebx và 'nghĩ' nó đã được thay đổi gần đây để nó chờ kết quả hoàn thành.

test ebx, ebx ; <-- CPU knows ebx was not altered, no stalls on subsequent reads. 
or ebx, ebx ; <-- CPU 'thinks' ebx was changed, stall on subsequent read. 

Nếu bạn muốn trạng thái zero để phản ánh trong sổ đăng ký khác, bạn có thể chỉ đơn giản là mov ebx để đăng ký khác.

Giảm một giá trị cho một boolean
Nếu bạn muốn giảm bớt đăng ký để một boolean (True nếu không, False khác), bạn sử dụng một trong những trình tự sau đây:

; ebx holds the value to reduce to a boolean. 
; eax is an unused register. 
xor eax, eax ; eax = 0 
sub eax, ebx ; eax = 0 - ebx; CF (carry flag) = 1 if ebx <> 0 
sbb ebx, ebx ; ebx = ebx - ebx - CF 
       ; <<-- ebx = -1 if non zero, 0 if zero 
xor eax, eax ; eax = 0 
sub eax, ebx ; eax = - ebx; CF = 1 if ebx <> 0 
adc ebx, eax ; ebx = (ebx + -ebx) aka 0 + CF 
       ; <<== ebx = 1 if non zero, 0 if zero 
test ebx, ebx ; force ZF to be correct 
setnz al  ; Store 1 if non-zero, 0 otherwise in byte register AL. 

Lưu ý rằng việc sử dụng thanh ghi byte có thể có vấn đề do các quầy hàng có liên quan đến "viết ghi một phần".

+0

Khi câu trả lời của Ped7g chỉ ra, 'neg ebx' đặt cờ từ' 0 - ebx' trong một hướng dẫn (nhưng cũng thay đổi giá trị ban đầu). –

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