call和jmp都是跳轉指令,但是call的同時會把pc地址壓入堆棧,並且這兩種方式都有遠和近跳轉。下麵的分析不全,因為沒有在網上找到足夠的資料,個人創造這個情景還是有些困難。 1.例子中的call的機器碼為0xe8。 0x400204ba <+30>: e8 41 b6 05 00 call 0x ...
call和jmp都是跳轉指令,但是call的同時會把pc地址壓入堆棧,並且這兩種方式都有遠和近跳轉。下麵的分析不全,因為沒有在網上找到足夠的資料,個人創造這個情景還是有些困難。
1.例子中的call的機器碼為0xe8。
0x400204ba <+30>: e8 41 b6 05 00 call 0x4007bb00 <__printf>
0x400204bf <+35>: c9 leave
問題:0x4007bb00是如何計算得來的?
pc = 0x400204bf(取完當前指令之後,pc指向下一條語句)
另一個因為是是在x86機器上,所以是小端,那麼下一個32位操作數就是0005b641,
pc + 操作數 =0x400204bf + 0x0005b641 = 0x4007bb00
2.jmp有多種跳轉:
2.1.如果是遠跳轉,操作數是一個32位數,機器碼e9
0x40011728 <+392>: e9 46 ff ff ff jmp 0x40011673 <_dl_open+211>
0x4001172d <+397>: 8b bb ec 04 00 00 mov 0x4ec(%ebx),%edi
計算方式和call(e8)一樣,0x4001172d + 0x ffffff46 = 0x40011673
2.2.如果是短跳轉,操作數8位數,機器碼eb
0x0804850d <+9>: c7 04 24 0a 00 00 00 movl $0xa,(%esp)
0x08048514 <+16>: e8 1f ff ff ff call 0x8048438 <sleep@plt>
0x08048519 <+21>: e8 0a ff ff ff call 0x8048428 <myprint@plt>
0x0804851e <+26>: eb ed jmp 0x804850d <main+9>
解:pc = 0x8048520
操作數 = 0xed
0x8048520 + 0xed - 0x100 = 0x804850d
情況2:0x4013b30d <+93>: eb ee jmp 0x4013b2fd <*__GI___libc_dlsym+77>
pc = 0x4013b30f
操作數 = 0xee
0x4013b30f + 0xee = 0x4013b3fd
0x4013b3fd - 0x100 = 0x4013b2fd
操作數-0x100就是操作數的補碼,最高位是符號位,若為1,則代表負數,若為0 代表正數。需要擴展符號位
0x4013b30f +0xffffffee = 0x4013b2fd
情況3: 0x4013b2d6 <+38>: 75 2b jne 0x4013b303 <*__GI___libc_dlsym+83>
0x4013b2d8 + 2b = 0x4013b303
2.3.如果是近跳轉,操作數是16位數
由於沒有找到合適的例子,個人覺得和短跳轉的計算方式是一樣的
2.4.以上都是相對跳轉,還有一種絕對跳轉,機器碼ff25
0x08048428 <+0>: ff 25 08 a0 04 08 jmp *0x804a008
0x0804842e <+6>: 68 10 00 00 00 push $0x10
0x08048433 <+11>: e9 c0 ff ff ff jmp 0x80483f
跳轉到0x0804a08中保存的地址。還是屬於間接跳轉。
其他的跳轉方式,等遇到了再補。