今天比较了一下goto语句和jmp语句的区别。
goto:
如果编译器检测到goto语句和目的地址之间的语句无法执行是,会忽略不会编译。
#include <iostream>
using namespace std;
int main()
{
cout<<"size of int : "<<sizeof(int)<<endl;
goto show_long;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
show_long:
cout<<"size of long : "<<sizeof(long)<<endl;
return 0;
}
编译结果为:
004015AA E8 31 FC FF FF call @ILT+475(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
6: goto show_long;
004015AF EB 2B jmp show_long+2Bh (004015dc)
7: cout<<"size of char : "<<sizeof(char)<<endl;
8: cout<<"size of char : "<<sizeof(char)<<endl;
9: show_long:
10: cout<<"size of long : "<<sizeof(long)<<endl;
004015B1 68 C8 10 40 00 push offset @ILT+195(std::endl) (004010c8)
注意到了,主要的两个地址goto语句的地址为0x004015AF,而下边两条语句没有编译,show_long指向的语句地址为0x004015B1.相差一个goto语句的长度。
jmp:
jmp后边操作数是目的地址与当前地址的偏移量。该操作数长度位1B或4B。视偏移量的长度而不同,但是只有该两种类型,换句话说,jmp语句的长度为2B或5B。验证如下:
1B型:
#include <iostream>
using namespace std;
unsigned int RetAddr;
__declspec(naked) void test_goto()
{
__asm pop RetAddr
RetAddr+=2; //偏移量为0x27,所以jmp的操作数为1B,所以地址量+2,可以跳过jmp语句。
__asm jmp RetAddr
}
int main()
{
cout<<"size of int : "<<sizeof(int)<<endl;
test_goto();
__asm jmp show_long;
cout<<"size of char : "<<sizeof(char)<<endl;
__asm show_long:
cout<<"size of long : "<<sizeof(long)<<endl;
return 0;
}
反编译部分代码为可以分析到jmp语句为2B长度,可计算出下边输出语句长度为0x27.
004015DA E8 01 FC FF FF call @ILT+475(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
13: test_goto();
004015DF E8 BF FC FF FF call @ILT+670(test_goto) (004012a3)
14: __asm jmp show_long;
004015E4 EB 27 jmp show_long (0040160d)
15:
16: cout<<"size of char : "<<sizeof(char)<<endl;
004015E6 68 C8 10 40 00 push offset @ILT+195(std::endl) (004010c8)
004015EB 6A 01 push 1
004015ED 68 30 E0 46 00 push offset string "size of char : " (0046e030)
004015F2 68 90 BE 47 00 push offset std::cout (0047be90)
004015F7 E8 89 FC FF FF call @ILT+640(std::operator<<) (00401285)
004015FC 83 C4 08 add esp,8
004015FF 8B C8 mov ecx,eax
00401601 E8 F9 FA FF FF call @ILT+250(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
00401606 8B C8 mov ecx,eax
00401608 E8 D3 FB FF FF call @ILT+475(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
17: __asm show_long:
18: cout<<"size of long : "<<sizeof(long)<<endl;
0040160D 68 C8 10 40 00 push offset @ILT+195(std::endl) (004010c8)
4B型:
#include <iostream>
using namespace std;
unsigned int RetAddr;
__declspec(naked) void test_goto()
{
__asm pop RetAddr
RetAddr+=5; //由于偏移量为0x0270,所以操作数为4B,则地址量+5,可以跳过jmp语句
__asm jmp RetAddr
}
int main()
{
cout<<"size of int : "<<sizeof(int)<<endl;
test_goto();
__asm jmp show_long;
cout<<"size of char : "<<sizeof(char)<<endl; //该语句的长度为0x27.
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
cout<<"size of char : "<<sizeof(char)<<endl;
__asm show_long:
cout<<"size of long : "<<sizeof(long)<<endl;
return 0;
}
可以分析出其中jmp语句的长度为5B。
004015DA E8 01 FC FF FF call @ILT+475(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
13: test_goto();
004015DF E8 BF FC FF FF call @ILT+670(test_goto) (004012a3)
14: __asm jmp show_long;
004015E4 E9 70 02 00 00 jmp show_long (00401859)
15:
16: cout<<"size of char : "<<sizeof(char)<<endl;
004015E9 68 C8 10 40 00 push offset @ILT+195(std::endl) (004010c8)