C语言到汇编-变量

2020-04-11  本文已影响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语言的控制流。

上一篇下一篇

猜你喜欢

热点阅读