zoukankan      html  css  js  c++  java
  • 裸函数及调用约定

    裸函数

      在函数名前面加上  __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
  • 相关阅读:
    C#深入浅出 修饰符(二)
    HDU 5785 Interesting
    HDU 5783 Divide the Sequence
    HDU 5781 ATM Mechine
    UVA 714 Copying Books
    uva 1471 Defense Lines
    UVA 11134 Fabled Rooks
    UVA 11572 Unique Snowflakes
    UVA 11093 Just Finish it up
    UVA 10954 Add All
  • 原文地址:https://www.cnblogs.com/zimudao/p/8321496.html
Copyright © 2011-2022 走看看