2008-09-29 34 views
101

Tôi đang cố gắng hiểu một số hội đồng.`testl` eax chống lại eax?

Việc lắp ráp như sau, tôi quan tâm trong dòng testl:

000319df 8b4508  movl 0x08(%ebp), %eax 
000319e2 8b4004  movl 0x04(%eax), %eax 
000319e5 85c0   testl %eax, %eax 
000319e7 7407   je  0x000319f0 

Tôi cố gắng để hiểu rằng điểm testl giữa %eax%eax? Tôi nghĩ rằng các chi tiết cụ thể của mã này không quan trọng, tôi chỉ cố gắng để hiểu bài kiểm tra với chính nó - sẽ không phải giá trị luôn luôn đúng?

Trả lời

73

Kiểm tra xem eax là 0 hoặc cao hơn hoặc thấp hơn. Trong trường hợp này, bước nhảy được thực hiện nếu eax là 0.

+0

Tôi đã chỉnh sửa để biến câu trả lời phổ biến này trở thành câu trả lời hợp lý hơn cho "điều TEST này là gì, và nó khác với CMP" như thế nào. Xem câu trả lời của riêng tôi tiếp tục cho ý kiến ​​về ý nghĩa ngữ nghĩa của JE đồng nghĩa và JZ. Vui lòng xem lại chỉnh sửa của tôi vì nó khá lớn và đó vẫn là câu trả lời của bạn. –

+0

@PeterCordes Tôi đánh giá cao ý định, nhưng tôi sẽ hoàn nguyên chỉnh sửa của bạn. 1. "Tiếng nói" của bạn rất khác so với tôi, và ngay bây giờ nó đọc rất giống câu trả lời của bạn hơn tôi. 2. Có nhiều vấn đề hơn là xác nhận táo bạo rằng các cờ xuất hiện chính xác theo cùng một cách giữa 'test' và' cmp'. Vâng, tôi hiểu đó là niềm tin của bạn dựa trên những bình luận của bạn với Cody. Tuy nhiên, đặt nó vào bài viết của tôi là một vấn đề khác; nó không phải là một khẳng định tôi sẵn sàng đứng, đơn giản chỉ vì _I không biết_ nếu nó giống hệt nhau trong mọi trường hợp. –

+0

@PeterCordes Tôi hiểu mong muốn có một câu trả lời "kinh điển", nhưng tôi nghĩ câu trả lời của bạn phải bơi hoặc chìm trên những giá trị riêng của nó, chứ không phải là câu trả lời được chấp nhận. Tôi đã phải làm điều đó cho một số câu trả lời của tôi cho câu hỏi rất phổ biến quá, giống như [nổi mồi điểm một] (http://stackoverflow.com/a/27030789/13), mà tại thời điểm gửi bài của tôi câu trả lời đã có câu trả lời khác với 500+ upvotes. –

82

Ý nghĩa của test là VÀ đối số cùng nhau và kiểm tra kết quả bằng không. Vì vậy, mã này kiểm tra nếu EAX là số không hay không. je sẽ nhảy nếu không.

BTW, điều này tạo ra một lệnh nhỏ hơn cmp eax, 0 đó là lý do mà trình biên dịch nói chung sẽ làm theo cách này.

3

Nếu eax là zero nó sẽ thực hiện các bước nhảy có điều kiện, nếu không nó sẽ tiếp tục thực hiện tại 319e9

31

Các hướng dẫn kiểm tra thực hiện một VÀ tác hợp lý giữa các toán hạng nhưng không ghi kết quả vào một thanh ghi. Chỉ các cờ được cập nhật.

Trong ví dụ của bạn kiểm tra eax, eax sẽ đặt cờ số không nếu eax bằng 0, cờ ký hiệu nếu đặt bit cao nhất và một số cờ khác.

Jump nếu lệnh Equal (je) nhảy nếu cờ zero được đặt.

Bạn có thể dịch mã để mã dễ đọc hơn như thế này:

cmp eax, 0 
je somewhere 

Đó có chức năng tương tự nhưng đòi hỏi một số byte nhiều mã không gian. Đó là lý do tại sao trình biên dịch phát ra một bài kiểm tra thay vì so sánh.

+3

Thực ra, cmp có thể không hoạt động ở đó. Đó là, nó hoạt động cho trường hợp cụ thể được trình bày, nhưng cmp ảnh hưởng đến cờ khác với kiểm tra, do nó là một phụ bên trong thay vì và. Một cái gì đó để giữ trong tâm trí. –

+4

cho một thử nghiệm với số không nó hoàn toàn hợp lệ. –

+3

Nhưng bạn không biết những gì khác nhìn vào những lá cờ sau đó. Các hiệu ứng trên cờ là rất khác nhau, vì vậy đây có thể là một vấn đề và rất thường xuyên. –

5

Đoạn mã này là từ một chương trình con đã được đưa ra một con trỏ đến một cái gì đó, có thể là một số cấu trúc hoặc đối tượng. Dòng thứ hai dereferences con trỏ, lấy một giá trị từ điều đó - có thể chính nó là một con trỏ hoặc có thể chỉ là một int, được lưu trữ như là thành viên thứ 2 của nó (offset +4). Các dòng thứ 3 và thứ 4 kiểm tra giá trị này cho số không (NULL nếu đó là một con trỏ) và bỏ qua một vài thao tác sau (không được hiển thị) nếu nó bằng 0. Các thử nghiệm cho không đôi khi được mã hóa như là một so sánh với một giá trị bằng không trực tiếp bằng chữ, nhưng trình biên dịch (hoặc con người?) Người đã viết này có thể nghĩ rằng một testl op sẽ chạy nhanh hơn - xem xét tất cả các công cụ CPU hiện đại như pipelining và đăng ký đổi tên. Đó là từ cùng một túi thủ thuật giữ ý tưởng thanh toán bù trừ một đăng ký với XOR EAX, EAX (mà tôi nhìn thấy trên tấm giấy phép của ai đó ở Colorado!) Chứ không phải là rõ ràng nhưng có thể chậm hơn MOV EAX, # 0 (tôi sử dụng một ký hiệu cũ hơn).

Trong asm, như perl, TMTOWTDI.

15

test giống như and, ngoại trừ nó chỉ viết CỜ, để lại cả hai yếu tố đầu vào chưa được sửa đổi. Với hai đầu vào khác nhau, nó rất hữu ích để kiểm tra xem một số bit có bằng không hoặc nếu ít nhất một giá trị được đặt. (ví dụ.test al, 3 đặt ZF nếu EAX là bội số của 4 (và do đó có cả 2 bit thấp của nó bằng 0).


test eax,eax bộ tất cả các lá cờ chính xác cùng một cách mà cmp eax, 0 sẽ:

  • CF và HÀNH xóa (AND/TEST luôn luôn làm điều đó, và trừ không bao giờ tạo ra một carry)
  • ZF, SF và PF theo giá trị trong EAX. (a = a&a = a-0)

(Ngoại trừ các lỗi thời cờ AF (phụ-carry, được sử dụng bởi các hướng dẫn ASCII/BCD). TEST leaves it undefined, nhưng CMP sets it "according to the result". Kể từ khi trừ zero không thể tạo ra một carry từ 4 đến chút 5th, CMP nên luôn luôn rõ ràng AF).


KIỂM TRA nhỏ hơn (không có ngay) và đôi khi nhanh hơn (có thể kết hợp macro thành uop so sánh và chi nhánh trên nhiều CPU hơn trong nhiều trường hợp hơn CMP). That makes test the preferred idiom for testing a register for zero or not.

Lý do phổ biến duy nhất để sử dụng CMP với 0 ngay lập tức là khi bạn muốn so sánh với toán hạng bộ nhớ (ví dụ: cmpb $0, (%esi) để kiểm tra byte không kết thúc ở cuối chuỗi C-style dài) .


AVX512F thêm kortestw k1, k2 và AVX512DQ/BW (Skylake nhưng không KNL) thêm ktestb/w/d/q k1, k2, mà hoạt động trên AVX512 thanh ghi mặt nạ (k0..k7) nhưng vẫn thiết FLAGS thường xuyên như test không, giống như cách mà số nguyên OR hoặc AND hướng dẫn.

kortestw k1,k1 là cách thành ngữ này sang cành/cmovcc/setcc dựa trên một AVX512 so sánh kết quả, thay thế SSE/AVX2 (v)pmovmskb/ps/pd + test hoặc cmp.


Sử dụng jz vs je thể gây nhầm lẫn.

jz and je are literally the same instruction, tức là cùng một mã opcode trong mã máy. Họ làm điều tương tự, nhưng có ý nghĩa ngữ nghĩa khác nhau cho con người. Disassemblers (và đầu ra asm thường từ các trình biên dịch) sẽ chỉ bao giờ sử dụng một, do đó sự khác biệt ngữ nghĩa bị mất.

cmpsub đặt ZF khi hai đầu vào của chúng bằng nhau (tức là kết quả trừ là 0). je (nhảy nếu bằng nhau) là từ đồng nghĩa có liên quan về ngữ nghĩa.

test %eax,%eax/and %eax,%eax lại đặt ZF khi kết quả bằng 0, nhưng không có kiểm tra "bình đẳng". ZF sau khi kiểm tra không cho bạn biết liệu hai toán hạng có bằng nhau hay không. Vì vậy, jz (nhảy nếu không) là từ đồng nghĩa ngữ nghĩa có liên quan.

+0

Tôi sẽ xem xét việc thêm các thông tin cơ bản về 'test' là bitwise' và' hoạt động, có thể không rõ ràng cho mọi người chỉ học lắp ráp (và lười biếng/không biết để kiểm tra hướng dẫn tham khảo hướng dẫn sau mỗi 60 giây;) :)). – Ped7g

+1

@ Ped7g: đủ công bằng, tôi đoán nó không làm tổn thương để đưa mọi thứ vào câu trả lời này, thay vì để phần đó cho các câu trả lời khác. Đã thêm AVX512 'kortest *' và 'ktest *' trong khi tôi đang ở đó. –

0

Trong một số chương trình, chúng có thể được sử dụng để kiểm tra tràn bộ đệm. Ở phía trên cùng của không gian được phân bổ một 0 được đặt.Sau khi nhập dữ liệu vào ngăn xếp, nó tìm kiếm 0 ngay từ đầu của không gian được phân bổ để đảm bảo không gian được cấp phát không bị tràn.

Nó được sử dụng trong việc thực hiện stack0 của khai thác-bài tập để kiểm tra xem nó đã được tràn và nếu có wasnt và đã có một số không ở đó, nó sẽ hiển thị "Thử lại"

0x080483f4 <main+0>: push ebp 
0x080483f5 <main+1>: mov ebp,esp 
0x080483f7 <main+3>: and esp,0xfffffff0 
0x080483fa <main+6>: sub esp,0x60      
0x080483fd <main+9>: mov DWORD PTR [esp+0x5c],0x0 ;puts a zero on stack 
0x08048405 <main+17>: lea eax,[esp+0x1c] 
0x08048409 <main+21>: mov DWORD PTR [esp],eax 
0x0804840c <main+24>: call 0x804830c <[email protected]> 
0x08048411 <main+29>: mov eax,DWORD PTR [esp+0x5c] 
0x08048415 <main+33>: test eax,eax     ; checks if its zero 
0x08048417 <main+35>: je  0x8048427 <main+51> 
0x08048419 <main+37>: mov DWORD PTR [esp],0x8048500 
0x08048420 <main+44>: call 0x804832c <[email protected]> 
0x08048425 <main+49>: jmp 0x8048433 <main+63> 
0x08048427 <main+51>: mov DWORD PTR [esp],0x8048529 
0x0804842e <main+58>: call 0x804832c <[email protected]> 
0x08048433 <main+63>: leave 
0x08048434 <main+64>: ret 
+0

Tôi không thấy trường hợp cụ thể nào của việc kiểm tra sổ đăng ký cho số không khác thêm vào phần Hỏi & đáp này. Đặc biệt khi 'cmp DWORD PTR [esp + 0x5c], 0' /' jz 0x8048427 'sẽ hiệu quả hơn một tải MOV riêng biệt và sau đó là TEST. Đây không phải là trường hợp sử dụng phổ biến để kiểm tra số không. –

-2

chúng ta có thể nhìn thấy jg, jle Nếu testl %edx,%edx. jle .L3 chúng ta dễ dàng có thể tìm jle là phù hợp với (SF^OF)|ZF, nếu% edx là zero, ZF = 1, nhưng nếu% edx không phải là zero và là -1, sau khi testl, OF = 0, và SF = 1, vì vậy cờ = true, mà thực hiện nhảy .xin lỗi, tiếng Anh của tôi kém

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