今天比较了一下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)