C/C++拾遗录--关于goto和jmp语句浅析

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


你可能感兴趣的:(c,String,basic,编译器)