zoukankan      html  css  js  c++  java
  • 汇编的艺术(01)sizeof operator

    以前在百度的博客里面学习了逆向一些基本的C语言知识。一方面不能让学习的汇编知识荒废,另外一方面是由于经常碰到一些细节性的问题,需要温故而知新。

    学习汇编对于我自己的感觉是:可以从更加底层的角度来窥视C语言以及其他高层语言的细节。这是一件很舒服的事情~

    同时一些特殊的工作,比如内核调试,内存错误,函数调用等问题,用汇编的角度来看待会更加方便,更加深刻的理解其机制。

    废话不多说,作为开篇《汇编的艺术》,是我今天更巧碰到的一个问题,想记下来,先从最简单的入手,感觉是慢慢来的~

    先看一段代码:

    int main()  
    {  
        char a = 255;  
        printf("%d\n",sizeof(++a));  
        printf("%d\n",a);  
        return 0;  
    }  

    出乎意料的是,输出的值是:1,-1

    难道是sizeof里面的++a没有执行么?带着这样的疑问,看看反汇编代码是啥样的:

    int main()  
    {  
        char a = 255;  
    00000000  push        ebp  
    00000001  mov         ebp,esp 
    00000003  sub         esp,8 
    00000006  cmp         dword ptr ds:[00192E14h],0 
    0000000d  je          00000014 
    0000000f  call        696E67F9 
    00000014  xor         edx,edx 
    00000016  mov         dword ptr [ebp-4],edx 
    00000019  mov         dword ptr [ebp-8],0 
    00000020  xor         edx,edx 
    00000022  mov         dword ptr [ebp-4],edx 
    00000025  mov         dword ptr [ebp-8],0FFFFFFFFh 
        printf("%d\n",sizeof(++a));  
    0000002c  push        1B31B8h 
    00000031  push        1    
    00000033  push        4F01B8h 
    00000038  call        FEEA58CC 
    0000003d  add         esp,0Ch 
    00000040  nop              
        printf("%d\n",a);  
    00000041  push        1B31BCh 
    00000046  push        dword ptr [ebp-8] 
    00000049  push        4F01C8h 
    0000004e  call        FEEA58CC 
    00000053  add         esp,0Ch 
    00000056  nop              
        return 0;  
    00000057  xor         edx,edx 
    00000059  mov         dword ptr [ebp-4],edx 
    }  
    0000005c  mov         eax,dword ptr [ebp-4] 
    0000005f  mov         esp,ebp 
    00000061  pop         ebp  
    00000062  ret              

    看到橙黄色标注的部分,果然传参的时候是直接push了1,而++a这个指令在没有在汇编中出现的痕迹。

    但是sizeof操作符并不像#define这样的宏一样在预处理阶段就把其替换掉了,sizeof是在编译阶段替换的。

    于是理解了,sizeof里面的expression都是不执行的,只关心里面类型的大小。

    类似的问题还有sizeof('a'),貌似不同的编译器说法不一,C标准应该是把'a'看成了97,也就是int类型,等于4,

    如果里面的数字再大的话,超过了int范围,则是8了,以此类推。

    还有是sizeof("a"),这个问题不该有争议,因为传进去的是字符串a的地址,就是一个指针的大小了,32位机器上面是4,64位机器上面应该是8.

    btw:

    很久没有看过反汇编代码了,很多东西都生疏了。

    比如说里面不理解的是,main()函数明明只申请了一个char 的却把栈空间抬高了8个字节,边界对齐为char开辟4字节还能理解。

    那另外的4个字节又是什么意思呢?函数最后返回的代码利用到了这4个字节,把里面的值传给eax。

    这是汇编的风格,函数的返回值是传给eax的。但是不清楚为什么还要“多此一举”。

    我的理解是,因为函数最终要返回的,对于一般的函数如果返回比如 return ans; ans变量肯定要开辟字节空间的,于是return 0; 也按照这个思路照做了?有时间再探究。

    第二个问题就是又一次的复习了函数传参时堆栈的情况。感觉都有点生疏了。

    printf 第一个参数压入的是格式化字符串的地址,后面压入的几个参数则是变量。对于这类参数可变的函数,平衡堆栈的工作要交给母函数来处理的。

    关于这方面详细的介绍请看:http://bbs.pediy.com/showthread.php?t=56518

    -------------------------------------------------------

    kedebug

    Department of Computer Science and Engineering,

    Shanghai Jiao Tong University

    E-mail: kedebug0@gmail.com

    GitHub: http://github.com/kedebug

    -------------------------------------------------------

  • 相关阅读:
    what is NSParameterAssert?
    scrollView的几个属性contentSize contentOffset contentInset
    Explain awakeFromNib, initwithFrame usage
    strong、weak、unsafe_unretained(ARC);retain
    iOS 面试记(二)
    Python 编程规范 by @AKaras
    Python 的类的下划线命名
    Python中数值和进制转换
    Python基本运算符
    Ubuntu Linux系统下轻松架设nginx+php服务器应用
  • 原文地址:https://www.cnblogs.com/kedebug/p/2800225.html
Copyright © 2011-2022 走看看