long long c语言_从C语言到汇编(一)变量

94591c833fe47020bc872de73930f6dc.png

是否有兴趣

每当我们用c语言编写程序时,我们是否会对怎么从一个c语言的文本文件,转化为可执行文件代码与数据感兴趣。

如果你有兴趣的话,本文可以帮助你理解从c到汇编的规则。

机器架构

本文在32位Ubuntu操作系统上运行,并使用gcc编译器编译。编译命令为gcc -S xxx.c 命令结束后会在当前文件夹下生成一个xxx.s文件。这就是汇编文件。可以查看其中汇编代码。

正式开始了

c语言中可以定义各种类型的变量。可以对变量做任何算数操作,位操作。变量就是一块内存区域,机器指令可以操作该内存区域。加减乘除取余指令与或非异或左移右移指令。

定义变量

c语言可以定义基本数据类型,数组,异构体变量。在这里我们只讲基本数据类型,数组和异构体会在后文中体现。

基本数据类型变量有字符型char unsigned char一字节,短整形short unsigend short二字节,整形int unsigned int 4字节,长整形long unsigned long4字节。

定义

int fun()
{
    char ch;
    unsigned char uch;
    short s;
    unsigned short us;
    int i; 
    unsigned int ui;
    long l;
    unsigned long ul;
}

汇编代码

        pushl   %ebp
        movl    %esp, %ebp
        subl    $32, %esp
        leave
        ret

pushl %ebp;movl %esp, %ebp;leave;ret。指令是用于构建函数使用的指令。我们可以暂时不看,以后会讲解。

subl $32, %esp向栈中申请了32字节。可以看出用户只申请了22个字节。但是C语言规定申请的用户空间为16字节的倍数,这是为了提高程序的运行效率。所以申请了32字节。32个字节中,-4(%ebp)为ul的内存地址,-8(%ebp)为l的地址,-12(%ebp)为ui的内存地址,-16(%ebp)为i的内存地址。-18(%ebp)为us的内存地址,-20(%ebp)为s的内存地址。-21(%ebp)为uch的内存地址,-22(%ebp)为ch的内存地址

赋值

int fun()
{
    char ch;
    unsigned char uch;
    short s;
    unsigned short us;
    int i;
    unsigned int ui;
    long l;
    unsigned long ul;

    ch=1;
    uch=2;
    s=3;
    us=4;
    i=5;
    ui=6;
    l=7;
    ul=8;
}

汇编代码

        pushl   %ebp
        movl    %esp, %ebp
        subl    $32, %esp
        //ch=1
        movb    $1, -22(%ebp)
        //uch=2
        movb    $2, -21(%ebp)
        //s=3
        movw    $3, -20(%ebp)
        //us=4
        movw    $4, -18(%ebp)
        //i=5
        movl    $5, -16(%ebp)
        //ui=6
        movl    $6, -12(%ebp)
        //l=7
        movl    $7, -8(%ebp)
        //ul=8
        movl    $8, -4(%ebp)
        nop
        leave
        ret

其中使用指令movb,movw,movl。

movb S,D S->D 传送字节

movw S,D S->D 传送字

movl S,D S->D 传送双字

S可以是立即数,寄存器,内存地址。D可以是寄存器,内存地址。S与D不能同时为内存地址。也就是说一个内存地址(变量)赋值给另一个内存地址(变量)需要2步操作。从内存赋值到寄存器,将寄存器赋值给内存。

数据扩展

int fun()
{
    char ch;
    unsigned char uch;
    short s;
    unsigned short us;
    int i;
    unsigned int ui;
    long l;
    unsigned long ul;
    
    i=ch;
    i=uch;
}

汇编代码

        pushl   %ebp
        movl    %esp, %ebp
        subl    $32, %esp
        movsbl  -22(%ebp), %eax
        movl    %eax, -16(%ebp)
        movzbl  -21(%ebp), %eax
        movl    %eax, -16(%ebp) 
        nop
        leave
        ret
int fun()
{
    char ch;
    unsigned char uch;
    short s;
    unsigned short us;
    int i;
    unsigned int ui;
    long l;
    unsigned long ul;
    
    i=s;
    i=us;
}

汇编代码

        pushl   %ebp
        movl    %esp, %ebp
        subl    $32, %esp
        movswl  -20(%ebp), %eax
        movl    %eax, -16(%ebp)
        movzwl  -18(%ebp), %eax
        movl    %eax, -16(%ebp) 
        nop
        leave
        ret

其中movsbl指令做了符号扩展的字节传送到双字。movsbl S->D S可以是寄存器,内存地址。D可以是寄存器,内存地址。不能同时为内存地址。movswl指令做了符号扩展的字传送到双字。指令用法同movsbl。

movzbl 指令做了零扩展的字节传送到双字。

movzwl 指令做了零扩展的字传送到双字。

指令用法同于movsbl。

从上面代码我们可以看到汇编代码按照C语言的语法规则老老实实的进行了转化。

语法规则为

如果其中一个操作数的类型为long double,另一个操作数就会装换为long double类型。
否则,如果其中一个操作数的类型位double,另一个操作数就会转换为double类型。
否则,如果其中一个操作数的类型为float,另一个操作数就会装换为float类型。
否则,在两个操作数上所执行的是整型提升,其规则如下:
如果其中一个操作数的类型位unsigned long,另一个操作数就会转换为unsigned long类型。
否则,如果其中一个操作数的类型为long,并且另一个操作数的类型为unsigned,有两种可能性:
1.如果long可以表示unsignd类型的所有值,那么这个unsigned类型的操作数被转换为long类型。
2.如果long无法表示unsigned类型的所有值,那么这两个操作数都被转换为unsigned long类型。
否则,如果其中一个操作数的类型是long,另一个操作数就会转换为long类型。
否则,如果其中一个操作数是unsigned ,另一个操作数就会转换为unsigned类型。
否则,两个操作数都转换位int类型。
符号变量整形提升时做符号转换过,无符号变量整形提升时做无符号装换

数据截断

int fun()
{
    char ch;
    unsigned char uch;
    short s;
    unsigned short us;
    int i;
    unsigned int ui;
    long l;
    unsigned long ul;

    ch=i;
    uch=i;
}

汇编代码

        pushl   %ebp
        movl    %esp, %ebp
        subl    $32, %esp
        movl    -16(%ebp), %eax
        movb    %al, -22(%ebp)
        movl    -16(%ebp), %eax
        movb    %al, -21(%ebp)
        nop
        leave
        ret
int fun()
{
    char ch;
    unsigned char uch;
    short s;
    unsigned short us;
    int i;
    unsigned int ui;
    long l;
    unsigned long ul;

    s=i;
    us=i;
}
        pushl   %ebp
        movl    %esp, %ebp
        subl    $32, %esp        
        movl    -16(%ebp), %eax
        movw    %ax, -20(%ebp)
        movl    -16(%ebp), %eax
        movw    %ax, -18(%ebp)
        nop
        leave
        ret
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值