08 变量和作用域,call

1. 全局变量

全局变量访问方式是立即数间接访问

普通全局变量和const全局常量分布在不同的内存分页中,satic全局变量和普通全局变量没有区别:

 

 

const int g_nTest1 = 123;

int g_nTest2 = 456;

static int g_nTest3 = 789;

 

int main(int argc, char *argv[]) {

    printf("%p %d\n", &g_nTest1, g_nTest1);

    printf("%p %d\n", &g_nTest2, g_nTest2);

printf("%p %d\n", &g_nTest3, g_nTest3);

return 0;

}

 

对于局部静态变量,存在一个是否初已始化的标志,防止重入,VC6代码逻辑如下:

 

 

VC6中,如果存在多个static局部变量,则用每个bit表示每个是否已初始化。

 

 

VS2019中为了防止多线程冲突,用了TLS,如果已初始化就把标志设为0x800000001, 0x800000002, 0x800000003等,下图00411A8C的一句里的0x104偏移是TLS数据所在位置,每个线程都有一个。

 

 

 

 

2. 局部变量

以返回地址为分界线,往0方向走的是局部变量,往地址增量方向走的是参数。

 

3. 堆变量

newdeletemallocfree可以靠函数签名识别,如果签名未识别出,跟到函数内部可以看到HeapAllocHeapFree等类似函数的调用。

 

4. 函数调用约定

extern "C"

int __fastcall Test1(int nParam1, int nParam2, int nParam3) {

    return nParam1 + nParam2 + nParam3;

}

 

extern "C"

int __cdecl Test2(int nParam1, int nParam2, int nParam3) {

    return nParam1 - nParam2 - nParam3;

}

 

extern "C"

int __stdcall Test3(int nParam1, int nParam2, int nParam3) {

    return nParam1 * nParam2 * nParam3;

}

 

以上代码按C的名称粉碎规则生成函数名:

__cdecl:      _Test2

__stdcall:      _Test3@12

__fastcall:     @Test1@12

 

如果函数内部没有平栈操作,考虑__cdecl

如果函数内部直接使用ecxedx的值,考虑__fastcall,函数内平栈

 

5. 函数返回值

返回char                  -> al -> movsx

返回unsigned char        -> al -> movzx

返回short                 -> ax -> movsx

返回unsigned short       -> ax -> movzx

返回int                   -> eax

返回unsigned int         -> eax

返回long long            -> edx.eax

返回unsigned long long  -> edx.eax

返回float   -> ST(0)xmm0

返回double   -> ST(0)xmm0

 

posted @ 2021-01-05 14:56  八转达人  阅读(79)  评论(0编辑  收藏  举报