Pregunta

Estoy tratando de entender un poco de ensamblaje.

El ensamblaje de la siguiente manera, estoy interesado en la línea testl :

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

Estoy tratando de entender ese punto de testl entre % eax y % eax ? Creo que los detalles de lo que este código no es importante, solo trato de entender la prueba por sí mismo, ¿no sería el valor siempre verdadero?

¿Fue útil?

Solución

Comprueba si eax es 0, o superior, o inferior. En este caso, el salto se realiza si eax es 0.

Otros consejos

El significado de test es para AND los argumentos juntos, y verifica el resultado para cero. Entonces este código prueba si EAX es cero o no. je saltará si es cero.

Por cierto, esto genera una instrucción más pequeña que cmp eax, 0 , que es la razón por la que los compiladores generalmente lo hacen de esta manera.

La instrucción de prueba realiza una operación AND lógica entre los operandos, pero no vuelve a escribir el resultado en un registro. Solo se actualizan las banderas.

En su ejemplo, la prueba eax, eax establecerá la bandera de cero si eax es cero, la bandera de signo si se establece el bit más alto y algunas otras banderas también.

La instrucción Saltar si igual (je) salta si se establece el indicador cero.

Puedes traducir el código a un código más legible como este:

cmp eax, 0
je  somewhere

Eso tiene la misma funcionalidad pero requiere algunos bytes más de espacio de código. Esa es la razón por la que el compilador emitió una prueba en lugar de una comparación.

test es como y , excepto que solo escribe FLAGS, dejando ambas entradas sin modificar. Con dos entradas diferentes , es útil para probar si algunos bits son todos cero, o si al menos uno está configurado. (por ejemplo, test al, 3 establece ZF si EAX es un múltiplo de 4 (y por lo tanto tiene sus 2 bits bajos puestos a cero).


prueba eax, eax establece todos señala exactamente de la misma forma que cmp eax, 0 sería :

  • CF y OF borrados (AND / TEST siempre hace eso; y restar cero nunca produce un carry)
  • ZF, SF y PF según el valor en EAX. ( a = a & amp; a = a-0 )

(Excepto por el AF obsoleto (indicador de transporte auxiliar, utilizado por las instrucciones ASCII / BCD). La PRUEBA lo deja sin definir , pero CMP lo establece " según el resultado " . Dado que restar cero no puede producir un acarreo desde el cuarto hasta el quinto bit, CMP siempre debe borrar el AF).


TEST es más pequeño (no inmediato) y, a veces, más rápido (se puede fusionar en una uop de comparación y ramificación en más CPU en más casos que en CMP). Eso hace que el test el idioma preferido para probar un registro para cero o no .

La única razón común para usar CMP con un 0 inmediato es cuando desea comparar con un operando de memoria (por ejemplo, cmpb $ 0, (% esi) para verificar un byte cero de terminación en el final de una cadena de estilo C de longitud implícita).


AVX512F agrega kortestw k1, k2 y AVX512DQ / BW (Skylake pero no KNL) agrega ktest / w / d / q k1, k2 , que operan en los registros de máscara AVX512 (k0..k7) pero aún establecen FLAGS regulares como test , de la misma manera que El entero OR o AND lo hacen.

kortestw k1, k1 es la forma idiomática de derivar / cmovcc / setcc basado en un resultado de comparación AVX512, reemplazando SSE / AVX2 (v) pmovmskb / ps / pd + test o cmp .


El uso de jz en lugar de je puede ser confuso.

jz y je son literalmente los La misma instrucción , es decir, el mismo código de operación en el código de la máquina. Hacen lo mismo, pero tienen un significado semántico diferente para los humanos . Los desensambladores (y normalmente los resultados de los compiladores) solo usarán uno, por lo que se pierde la distinción semántica.

cmp y sub establecen ZF cuando sus dos entradas son iguales (es decir, el resultado de la resta es 0). je (saltar si es igual) es el sinónimo semánticamente relevante.

test% eax,% eax / y% eax,% eax nuevamente establece ZF cuando el resultado es cero, pero no hay una igualdad de " " prueba. ZF después de la prueba no te dice si los dos operandos eran iguales. Entonces jz (saltar si es cero) es el sinónimo semánticamente relevante.

Este fragmento de código proviene de una subrutina que recibió un puntero a algo, probablemente alguna estructura u objeto. La segunda línea hace referencia a ese puntero y obtiene un valor de esa cosa, posiblemente un puntero o tal vez solo un int, almacenado como su segundo miembro (desplazamiento +4). Las líneas 3 y 4 prueban este valor en cero (NULL si es un puntero) y omite las siguientes operaciones (no se muestran) si es cero.

La prueba de cero a veces se codifica como una comparación con un valor cero literal inmediato, pero el compilador (¿o el humano?) que escribió esto podría haber pensado que una operación de prueba se ejecutaría más rápido, teniendo en cuenta todas las cosas modernas de la CPU como Canalización y cambio de nombre de registro. Es de la misma bolsa de trucos que contiene la idea de borrar un registro con XOR EAX, EAX (¡que vi en la matrícula de alguien en Colorado!) En lugar del MOV EAX obvio pero tal vez más lento, # 0 (uso una notación anterior) ).

En asm, como perl, TMTOWTDI.

Si eax es cero, realizará el salto condicional; de lo contrario, continuará con la ejecución en 319e9

En algunos programas se pueden usar para verificar un desbordamiento de búfer. En la parte superior del espacio asignado se coloca un 0. Después de ingresar los datos en la pila, busca el 0 al comienzo del espacio asignado para asegurarse de que el espacio asignado no esté desbordado.

Se usó en el ejercicio de ejercicios de exploits de la pila0 para comprobar si estaba desbordado y si no había y había un cero allí, se mostraría " Intentar nuevamente "

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 <gets@plt>
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 <puts@plt>
0x08048425 <main+49>:   jmp    0x8048433 <main+63>
0x08048427 <main+51>:   mov    DWORD PTR [esp],0x8048529
0x0804842e <main+58>:   call   0x804832c <puts@plt>
0x08048433 <main+63>:   leave
0x08048434 <main+64>:   ret

podríamos ver jg & # 65292; jle Si testl% edx,% edx. jle .L3 podríamos encontrar fácilmente jle se adapta a (SF ^ OF) | ZF , si% edx es cero, ZF = 1, pero si% edx no es cero y es -1, después de la prueba, la OF = 0 y la SF = 1, por lo que la bandera = verdadera, que implementa el salto Lo siento, mi inglés es pobre

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top