How do we use jump in assembly using these instruc

2020-04-30 09:31发布

问题:

I understand that jump in assembly is basically going from one location to another.

Say we have

804828f: 74 05            je XXXXXXX
8048291: e8 1e 00 00 00 call 80482b4 

According to the book, all I'm really doing is adding 0x05 to 8048291 which yields 8048291, but I am confused by what the command here is asking. According to the book, operand je is je which is equal / 0

Then we have a complicated one that I really am having a hard time wrapping my head around.

8048357: 72 e7                        jb XXXXXXXX
8048359: c6 05 10 a0 04 08 01 movb $0x1,0x804a010

According to this, since e7 is the 1bit signed representation of -25, jb goes to address 8048340.

That. . . Makes NO sense to me. . . AT ALL. For one, if something is signed and 1-byte shouldn't its maximum value just be 2? Secondly, if something is -25, then why is the origin 8048340? How did we go from 59 to 40 if there was no 19 involved?

What I think the answer is:

I had this in my mind for a second, but to get 19 from hex 25, should I divide 16 by 25, seize its remainder which is 9 and then add 9 to 10 which is what 1 stands for in this case?

I'm honestly lost on having a signed single byte value though.

回答1:

Branching in assembly is flexible, in a sense that you can arrange the code blocks in any order you want. You can also merge the branches by jumping to the same block. To archive this the instructions must to able to jump both forward and backward. The following example shows a use of backward jumping.

073000:  bf 08 00 00 00          mov    edi, 0x8
073005:  31 c0                   xor    eax, eax
073007 <loop>:
073007:  01 f8                   add    eax, edi
073009:  83 ef 01                sub    edi, 0x1
07300c:  75 f9                   jne    073007 <loop>
07300e:

To jump forward the number following the Opcode is positive; to jump backward the number following the Opcode is negative. In a binary world the sign of a number is determined by its highest bit. In the example hex f9 is binary 11111001 and means -7 (see below for how to convert). Because hex(07300e) - 7 is hex(073007), it will jump to 073007 is ZF if not set (that means edi is not zero after subtraction in the above example).

It seems to me that you are confused by the hexadecimal numbers. I will use a few example to show how to convert them to decimal numbers. Google and you can find more detail.

Unsigned numbers:
0x1234 =  1*16^3 +  2*16^2 + 3*16^1 +  4 = 4660 
0x3420 =  3*16^3 +  4*16^2 + 2*16^1 +  0 = 13344 
0x0A0B =  0*16^3 + 10*16^2 + 0*16^1 + 11 = 2571   (A is 10; B is 11)
0x8000 =  8*16^3 +  0*16^2 + 0*16^1 +  0 = 37268
0xFF7A = 15*16^3 + 15*16^2 + 7*16^1 + 10 = 65402  (F is 15)

Signed numbers:
0x1234 =   ; positive because 1 is smaller than 8
0x3420 =   ; positive because 3 is smaller than 8 
0x0A0B =   ; positive because 0 is smaller than 8
0x8000 =   ; negative because 8 is NOT smaller than 8
0xFF7A =   ; negative because F (15) is NOT smaller than 8

Signed numbers:
0x1234 = 4460  ; positive numbers are calculated like unsigned number
0x3420 = 13344 ; positive numbers are calculated like unsigned number
0x0A0B = 2571  ; positive numbers are calculated like unsigned number
0x8000 = 32768 - 65536 = -32768 ; a simple way to calculate negative number
0xFF7A = 65402 - 65536 = -134 ; a simple way to calculate negative number

When the first digit is >= 8, the highest bit is 1 so the number is negative.

65536 is 2^16.



回答2:

0x05 + 0x8048291 is 0x8048296. You seem to have added zero, not 5. It's a conditional jump over the 5-byte call, and is taken if ZF is set. (http://felixcloutier.com/x86/Jcc.html).

x86 branch displacements are relative to the end of the branch instruction, i.e. the start of the next instruction.

The addresses are in hex, not decimal, even though they don't start with 0x in the disassembly output. Notice that 804828f includes f as a digit. Displacements are 1 byte, not 1 bit, and thus have a range of -128 to +127. There's a different encoding for rel32 jumps in case rel8 is out of range.

Intel's manual explains the encoding (2's complement sign extended relative displacement) and range: https://www.felixcloutier.com/x86/jmp