Estou tentando entender alguma montagem.
A montagem da seguinte forma, estou interessado na testl
linha:
000319df 8b4508 movl 0x08(%ebp), %eax
000319e2 8b4004 movl 0x04(%eax), %eax
000319e5 85c0 testl %eax, %eax
000319e7 7407 je 0x000319f0
Estou tentando entender esse ponto testl
entre %eax
e %eax
? Acho que as especificações desse código não são importantes, estou apenas tentando entender o teste por si mesmo - o valor não seria sempre verdadeiro?
assembly
x86
instructions
maxpinguim
fonte
fonte
test
ecmp
. Sim, entendo que essa é sua crença com base em seus comentários para Cody. No entanto, colocá-lo na minha postagem é uma questão diferente; não é uma afirmação que eu esteja disposto a apoiar, simplesmente porque não sei se é idêntica em todos os casos.je
,jz
,cmp
, etest
, e não JE, JZ, CMP, ou TEST. Eu sou exigente assim.test a,a
ecmp $0,a
definir sinalizadores de forma idêntica; obrigado por apontar que essa é uma afirmação não trivial. re: TESTE vstest
.: recentemente comecei a usar letras maiúsculas como os manuais da Intel. Mas quando estou falando sobre mnemônicos da AT&T vs. mnemônicos da Intel, usotestb
estilo para a AT&T. IDK se isso ajuda na legibilidade.O significado de
test
é para AND os argumentos juntos e verifique o resultado para zero. Portanto, este código testa se EAX é zero ou não.je
irá pular se for zero.BTW, isso gera uma instrução menor do
cmp eax, 0
que a razão pela qual os compiladores geralmente fazem isso dessa maneira.fonte
A instrução de teste faz uma operação lógica AND entre os operandos, mas não escreve o resultado de volta em um registrador. Apenas os sinalizadores são atualizados.
Em seu exemplo, o teste eax, eax definirá o sinalizador zero se eax for zero, o sinalizador se for o bit mais alto definido e alguns outros sinalizadores também.
A instrução Jump if Equal (je) salta se o sinalizador zero estiver definido.
Você pode traduzir o código para um código mais legível como este:
Isso tem a mesma funcionalidade, mas requer alguns bytes a mais espaço de código. Essa é a razão pela qual o compilador emitiu um teste em vez de uma comparação.
fonte
test eax, eax
ecmp eax, 0
ambos definem todos os sinalizadores e os definem com valores idênticos. Ambas as instruções definem todos os sinalizadores "de acordo com o resultado". A subtração0
nunca pode produzir transporte ou transbordamento. Seu argumento está correto para qualquer imediato diferente de 0, mas não para 0.test
é semelhanteand
, exceto que apenas grava FLAGS, deixando ambas as entradas inalteradas. Com duas entradas diferentes , é útil para testar se alguns bits são todos zero ou se pelo menos um está definido. (por exemplo:test al, 3
define ZF se EAX é um múltiplo de 4 (e, portanto, tem ambos os 2 bits inferiores zerados).test eax,eax
define todos os sinalizadores exatamente da mesma maneira quecmp eax, 0
faria :a = a&a = a-0
).(PF como sempre só é definido de acordo com os 8 bits baixos )
Exceto para o AF obsoleto (sinalizador de transporte auxiliar, usado pelas instruções ASCII / BCD). TEST deixa indefinido , mas CMP o configura "de acordo com o resultado" . Uma vez que subtrair zero não pode produzir um transporte do 4º para o 5º bit, o CMP deve sempre limpar o AF.
TEST é menor (não imediato) e às vezes mais rápido (pode fundir macro em um uop de comparação e ramificação em mais CPUs em mais casos do que CMP). Isso torna
test
o idioma preferido para comparar um registro com zero . É uma otimização de olho mágico paracmp reg,0
que você pode usar independentemente do significado semântico.O único motivo comum para usar CMP com um 0 imediato é quando você deseja comparar com um operando de memória. Por exemplo,
cmpb $0, (%esi)
para verificar se há um byte zero de terminação no final de uma string estilo C de comprimento implícito.AVX512F adiciona
kortestw k1, k2
e AVX512DQ / BW (Skylake-X mas não KNL) adicionaktestb/w/d/q k1, k2
, que opera em registradores de máscara AVX512 (k0..k7), mas ainda define FLAGS regulares comotest
faz, da mesma forma que inteirosOR
ouAND
instruções fazem. (Maisptest
ou menos como SSE4 ou SSEucomiss
: entradas no domínio SIMD e resultam em FLAGS inteiros.)kortestw k1,k1
é a maneira idiomática de ramificar / cmovcc / setcc com base em um resultado de comparação AVX512, substituindo SSE / AVX2(v)pmovmskb/ps/pd
+test
oucmp
.O uso de
jz
vs.je
pode ser confuso.jz
eje
são literalmente a mesma instrução , ou seja, o mesmo opcode no código de máquina. Eles fazem a mesma coisa, mas têm significados semânticos diferentes para humanos . Os desmontadores (e normalmente a saída do conjunto de compiladores) usarão apenas um, portanto, a distinção semântica é perdida.cmp
esub
defina ZF quando suas duas entradas forem iguais (ou seja, o resultado da subtração é 0).je
(pule se for igual) é o sinônimo semanticamente relevante.test %eax,%eax
/and %eax,%eax
novamente define ZF quando o resultado é zero, mas não há teste de "igualdade". ZF após o teste não informa se os dois operandos eram iguais. Portanto,jz
(pule se zero) é o sinônimo semanticamente relevante.fonte
test
bit a bitand
, pode não ser óbvio para pessoas que estão aprendendo a montagem (e sendo preguiçoso / desatento para verificar o guia de referência de instrução a cada 60 segundos;) :)).kortest*
ektest*
enquanto eu estava nisso.Este trecho de código é de uma sub-rotina que recebeu um ponteiro para algo, provavelmente alguma estrutura ou objeto. A segunda linha desreferencia esse ponteiro, obtendo um valor daquela coisa - possivelmente um ponteiro ou apenas um int, armazenado como seu segundo membro (deslocamento +4). A 3ª e 4ª linhas testam este valor para zero (NULL se for um ponteiro) e pule as seguintes operações (não mostradas) se for zero.
O teste para zero às vezes é codificado como uma comparação com um valor zero literal imediato, mas o compilador (ou humano?) Que escreveu isso pode ter pensado que uma operação de teste seria executada mais rápido - levando em consideração todas as coisas da CPU moderna, como pipelining e registro renomeando. É o mesmo pacote de truques que contém a ideia de limpar um registro com XOR EAX, EAX (que eu vi na placa de alguém no Colorado!) Em vez do óbvio, mas talvez mais lento MOV EAX, # 0 (eu uso uma notação mais antiga )
Em asm, como perl, TMTOWTDI.
fonte
Se eax for zero, ele executará o salto condicional, caso contrário, continuará a execução em 319e9
fonte
Em alguns programas, eles podem ser usados para verificar se há estouro de buffer. No topo do espaço alocado, um 0 é colocado. Depois de inserir os dados na pilha, ele procura o 0 no início do espaço alocado para garantir que o espaço alocado não seja estourado.
Foi usado no exercício stack0 de exercícios de exploração para verificar se estava estourado e se não havia e havia um zero ali, ele exibia "Tente novamente"
fonte
cmp DWORD PTR [esp+0x5c], 0
/jz 0x8048427 <main+51>
teria sido mais eficiente do que uma carga MOV separada e, em seguida, TESTE. Este não é um caso de uso comum para verificar um zero.poderíamos ver o jg,jle Se
testl %edx,%edx. jle .L3
pudéssemos encontrar facilmente jle é o terno(SF^OF)|ZF
, se% edx for zero, ZF = 1, mas se% edx não for zero e for -1, após o teste, o OF = 0 e o SF = 1, então o flag = true, que implementa o salto. Desculpe, meu inglês é ruimfonte