• 裸函数及调用约定


    裸函数

      在函数名前面加上  __deplspec(naked),此时,编译器对该函数不会进行任何处理。

      想要在c语言里面写汇编的语法,使用vc中输入__asm

      对于一个裸函数而言,就是编译器不会为这个函数生成代码,想用汇编怎么写就怎么写,如果什么都不写,一定会报错,因为没有生成ret。

      

     1 #include<stdio.h>
     2 void __deplspec(naked) Function()
     3 {
     4     __asm
     5         {
     6             //保留栈底
     7             push ebp    ;此时 esp=esp+4
     8             //提升栈底
     9             mov ebp,esp    ;此时 ebp=esp
    10             sub esp,0x40    ;此处0x40即为缓冲区大小,可写任意数值
    11             
    12             //保存现场
    13             push ebx
    14             push edi
    15             push esi
    16             
    17             //往缓冲区中写入数据
    18             mov eax,0xCCCCCCCC
    19             ;0xCCCC在gb2312中是烫字,写C语言的时候出现烫烫烫就是这个原因,屯屯屯是0xCDCD,是堆的问题
    20             mov ecx,0x10    ;此处的0x10是0x40除以4得到的
    21             lea edi,dword ptr ds:[ebp-0x40]
    22             rep stosd
    23 
    24             //实现函数功能的地方
    25             
    26             //恢复现场
    27             pop esi
    28             pop edi
    29             pop ebx
    30             //降低栈底
    31             mov esp,ebp    ;降低esp
    32             pop ebp    ;降低ebp
    33             ret 
    34         }
    35 
    36 }
    37 
    38 void main()
    39 {
    40     Function();
    41 }     

    在上面的例子中,我没有传入参数,假如传递参数,一般是在函数调用前push入堆栈,具体再后面会提到。

    实现两个数之和的代码:

     1 #include<stdio.h>
     2 void __deplspec(naked) Add(int x,int y)
     3 {
     4     __asm
     5         {
     6             //保留栈底
     7             push ebp    ;此时 esp=esp+4
     8             //提升栈底
     9             mov ebp,esp    ;此时 ebp=esp
    10             sub esp,0x40    ;此处0x40即为缓冲区大小,可写任意数值
    11             
    12             //保存现场
    13             push ebx
    14             push edi
    15             push esi
    16             
    17             //往缓冲区中写入数据
    18             mov eax,0xCCCCCCCC
    19             ;0xCCCC在gb2312中是烫字,写C语言的时候出现烫烫烫就是这个原因,屯屯屯是0xCDCD,是堆的问题
    20             mov ecx,0x10    ;此处的0x10是0x40除以4得到的
    21             lea edi,dword ptr ds:[ebp-0x40]
    22             rep stosd
    23             //实现两个数之和的功能
    24             mov eax,dword ptr ds:[ebp+0x8]
    25             add eax,dword ptr ds:[ebp+0xC]
    26             
    27             
    28             //恢复现场
    29             pop esi
    30             pop edi
    31             pop ebx
    32             //降低栈底
    33             mov esp,ebp    ;降低esp
    34             pop ebp    ;降低ebp
    35             ret 8
    36         }
    37 
    38 }
    39 
    40 void main()
    41 {
    42     add(2,3);
    43 }     

    假如存在局部变量,局部变量的存储地方是在缓冲区中。例如,

    实现参数求和之后在加上一个常数z的代码:

     1 #include<stdio.h>
     2 void __deplspec(naked) Add(int x,int y)
     3 {
     4     __asm
     5         {
     6             //保留栈底
     7             push ebp    ;此时 esp=esp+4
     8             //提升栈底
     9             mov ebp,esp    ;此时 ebp=esp
    10             sub esp,0x40    ;此处0x40即为缓冲区大小,可写任意数值
    11             
    12             //保存现场
    13             push ebx
    14             push edi
    15             push esi
    16             
    17             //往缓冲区中写入数据
    18             mov eax,0xCCCCCCCC
    19             ;0xCCCC在gb2312中是烫字,写C语言的时候出现烫烫烫就是这个原因,屯屯屯是0xCDCD,是堆的问题
    20             mov ecx,0x10    ;此处的0x10是0x40除以4得到的
    21             lea edi,dword ptr ds:[ebp-0x40]
    22             rep stosd
    23             
    24             //实现的功能
    25             mov dword ptr ds:[ebp-0x4],1    ;ebp-0x4处存放局部变量z,z=1
    26             
    27             mov eax,dword ptr ds:[ebp+0x8]
    28             add eax,dword ptr ds:[ebp+0xC]
    29             add eax,dword ptr ds:[ebp+0x10]
    30             ;参数之和部分
    31             
    32             add eax,dword ptr ds:[ebp-0x4]    ;局部变量求和的部分
    33             
    34             //恢复现场
    35             pop esi
    36             pop edi
    37             pop ebx
    38             //降低栈底
    39             mov esp,ebp    ;降低esp
    40             pop ebp    ;降低ebp
    41             ret 0xC
    42         }
    43 
    44 }
    45 
    46 void main()
    47 {
    48     add(2,3,4);
    49 }     

    根据代码可以得到,局部变量存放在ebp-0x4开始往低地址,参数是存放在ebp+0x8开始

    调用约定

    外平栈是指在函数外面平衡堆栈

    内平栈是指在函数内部平衡堆栈

    例如上面的例子中最后ret 0xC,就是内平栈,因为是在函数内部

    外平栈一般是这样

    call   myfunction
    add esp,xxxxx
    ;且ret后面无数字
    
    call myfunction
    call function_pinghengduizhan
  • 相关阅读:
    根据View获取该控制器
    富文本
    自定义cell,根据数据源,要对cell的布局进行调整,没有实现调整的相应效果
    NSTimer定时器
    textFiled输入字数的控制问题之—把带输入的拼音也判断了
    iOS 最值宏定义
    ios7.1 masonry布局中出现的问题
    串行队列、并行队列、同步、异步
    商标数字整数申请流程
    商标网上申请流程
  • 原文地址:https://www.cnblogs.com/zimudao/p/8321496.html
Copyright © 2020-2023  润新知