美文网首页
C语言到汇编-变量

C语言到汇编-变量

作者: 故事观察日记 | 来源:发表于2020-04-11 14:58 被阅读0次

    变量,类似于汇编中的标号,例如:

    data segment
    year dw 0
    data ends
    

    这段代码中的year 就是一个标号,它实际上指的是一个长度为2个字节(dw)的内存空间的地址,它的初始值是0。在C语言中,定义变量的格式是:

    int year = 0;  
    

    这段代码的意思是定义了一个int 类型的变量,变量名为year ,初始值为0。int 类型的取值范围取决于具体的机器。通常是16位,也就是2个字节,也有用32位表示的。
    以上两种定义year 初始值的二进制值皆为“00000000 00000000”。(假设int 为16位)
    定义变量后,就可以为变量赋予不同的值了,比如:

    year = 1998;
    

    对应的汇编语言:

    mov year, 1998
    

    C语言的基本数据类型有:

    int 整数型
    float 浮点型 
    char 字符型(一个字节)
    short 短整型
    long 长整型
    double 双精度浮点型
    

    C语言有关变量的一些细节知识与其他语言(如Java)并没有什么不同,不再细说。
    看一个C语言变量的示例代码:

    int year = 1998;
    main() 
    { 
      int x = 7;
      int y = 9;
      float z = 3.5;
      z = x + y;
    }
    

    将这段代码保存在var.c 文件中,并用gcc 指令将其编译为汇编代码:

    gcc -S var.c -masm=intel
    

    得到汇编代码为:

        .file   "var.c"
        .intel_syntax
    .globl _year
        .data
        .align 4
    _year:
        .long   1998
        .def    ___main;    .scl    2;  .type   32; .endef
        .text
    .globl _main
        .def    _main;  .scl    2;  .type   32; .endef
    _main:
        push    ebp
        mov ebp, esp
        sub esp, 24
        and esp, -16
        mov eax, 0
        add eax, 15
        add eax, 15
        shr eax, 4
        sal eax, 4
        mov DWORD PTR [ebp-16], eax
        mov eax, DWORD PTR [ebp-16]
        call    __alloca
        call    ___main
        mov DWORD PTR [ebp-4], 7
        mov DWORD PTR [ebp-8], 9
        mov eax, 0x40600000
        mov DWORD PTR [ebp-12], eax
        mov eax, DWORD PTR [ebp-8]
        add eax, DWORD PTR [ebp-4]
        push    eax
        fild    DWORD PTR [esp]
        lea esp, [esp+4]
        fstp    DWORD PTR [ebp-12]
        leave
        ret
    
    

    去掉不关心的内容后:

    .globl _year
        .data  //.data通知as汇编后续语句,将它们追加在编号为0的数据段末。
        .align 4  //增加位置计数器(在当前的子段)使它指向规定的存储边界。
    _year:
        .long   1998  //.long expressions 每个expressions都生成一个数字,这个数字等于表达式在目标机器运行时的值。等价于.int。
    _main:
        mov DWORD PTR [ebp-4], 7
        mov DWORD PTR [ebp-8], 9
        mov eax, 0x40600000
        mov DWORD PTR [ebp-12], eax
        mov eax, DWORD PTR [ebp-8]
        add eax, DWORD PTR [ebp-4]
        push    eax
        fild    DWORD PTR [esp]
        lea esp, [esp+4]
        fstp    DWORD PTR [ebp-12]
        leave
        ret
    

    .data 是另一种定义数据段的方式,等价于:

    data segment
    data ends
    

    类似的还有.code,.stack 等。(参考《Intel汇编语言设计 第五版》 3.18节 伪指令。王爽的《汇编语言》只是入门,很多内容都没讲,所以找了本更全面的书当做参考工具书。)
    可以看到汇编代码中全局变量year 的定义,除了一些细节,基本与文章开头处的定义方式一致:

    data segment
    year dw 0
    data ends
    
    .globl _year
        .data
    _year:
        .long   1998
    

    再看其他代码的对比:

    int x = 7;
    int y = 9;
    float z = 3.5;
    z = x + y;
    
    mov DWORD PTR [ebp-4], 7
    mov DWORD PTR [ebp-8], 9
    mov eax, 0x40600000
    mov DWORD PTR [ebp-12], eax
    mov eax, DWORD PTR [ebp-8]
    add eax, DWORD PTR [ebp-4]
    push    eax
    fild    DWORD PTR [esp]
    lea esp, [esp+4]
    fstp    DWORD PTR [ebp-12]
    

    通过对比可以明显的看出,3个变量的值被依次压入了类似栈结构的内存空间中,每个值占4个字节,即32位。(前4行)
    接着将变量x 和y 的值取出来进行相加,再将结果压入栈中。(5-7行)
    最后将整数型结果转为浮点型。(8-10行)
    几个新汇编指令:
    fild指令:把整数转换成浮点数并加载至寄存器栈。
    lea指令:计算并装入16位或32位的内存操作数的有效地址。LEA指令获取的地址是在运行时进行计算的。
    fstp指令:存储浮点值并出栈。
    最后一行指令,将转换完的结果从栈中弹出存入[ebp-12] 内存单元:

    fstp    DWORD PTR [ebp-12]
    

    而根据前面4、5两行代码可以看出,[ebp-12] 内存单元存放的即是变量z 的值:

    mov eax, 0x40600000  //浮点数3.5的值
    mov DWORD PTR [ebp-12], eax
    

    好了,关于变量就先学到这里,下一篇开始学习C语言的控制流。

    相关文章

      网友评论

          本文标题:C语言到汇编-变量

          本文链接:https://www.haomeiwen.com/subject/dfkymhtx.html