理解计算机系统_程序的机器级表示(特别篇):对比move和leaq看汇编语言中数据的传递,变量和指针的映射,指针的实现

前言


       以<深入理解计算机系统>(以下称“本书”)内容为基础,对程序的整个过程进行梳理。本书内容对整个计算机系统做了系统性导引,每部分内容都是单独的一门课.学习深度根据自己需要来定

引入

        汇编代码传递数据的机制令人费解.而这部分内容又是比较基础的,需要有个清楚的认识,所以专门列一篇帖子来探索.move指令和leaq指令的区别,其他指令可以类比这两个指令.

        本贴主要讲几个方面内容:move指令和leaq的对比,变量指针的映射,以及指针的实现.

一.move指令和leaq的对比

        前面理解计算机系统_程序的机器级表示(二):寄存器,操作数,数据传送,程序栈-CSDN博客提到了数据的模型,由地址和数值组成.在汇编代码的指令中,数据是以立即数和地址出现的. 所有的指令都是在yo地址(操作数指示符的内容有阐述),或以立即数形式出现.

        然而在不同指令中的地址,表达的意思可能不一致,有的是地址,有的是数值.

        例如:move指令操作数值;leaq指令操作地址.如图所示

        笔者觉得其他指令对数据的操作可以参照这两个指令,操作数值或地址(二选一)

        示例代码:

movew $0x3,0xff00   //讲0x3传给地址0xff00
movew 0xff00,%ax    //讲0xff00里的数值传给%ax,此时%ax里的值是0x3

leaq 0xff00,%rax    //%rax里的值是0xff00

二.变量和指针的映射

        计算机内部对数据的存储,只有0和1两种状态.数据模型中,地址值和数值,表达方式是一样的,通常用十六进制0x来表示.

        寄存器或内存中存放的数值,由程序员的使用方式来决定他们是具体的数字还是地址.例如:

movew $0x3,0xff00
movew $0xff00,0xff40
movew 0xff40,%ax 

        此时%ax表示从0xff40传入的值,即0xff00.而(%rax)表示取以传进来的值0xff00,为地址的值0x3.

        汇编语言中的数据和高级语言的数据表示

          汇编语言中的数据,地址和数值是一体的,既没有"数据类型"这个概念(有数据长度的区分),也没有明确区分"数值"和"指针",由使用者自己解释.高级语言不但区分了数据类型,在类型相同的情况下还区分出了"变量"和"指针" .  下面试着找他们的映射关系(伪代码不保证准确只谈思路)

        1>变量  

      以下两种写法的结果看起来差不多

//汇编指令
movew $0x3,0xff00 
//c语言写法
short int a=3;   

        在C语言代码中,变量a的底层是一个地址0xff00,所以变量相当于给地址取了个名称.这样做的好处是方便程序员表达,以及使用者的理解.当然还有其他问题要解决,比如short类型是怎样定义的,和其他类型是怎么区分的.这个问题是编译器设计者解决的,只是使用可以不用关心.

        2>指针

        以下两种写法的结果差不多(忽略数据类型)

//汇编指令
movew $0x3,0xff00 
leaq 0xff00,%rax
moveq %rax,0xff08    //将地址0xff00放入0xff08
movew $0x4,(0xff08)  //0xff08的值等于0xff00,加括号取以0xff00为地址的值并修改为4

//c语言写法
short int a=3;   
short int* p=&a;
*p=4;                //修改a地址的数据为4

        变量a的地址0xff00,他的指针p的值被设置为0xff08.

        观察一下难道不是多此一举吗?C语言中特意多用了一个字(2个字节)的空间来放地址

movew $0x4,0xff00   //替代C语言的汇编代码

        C语言如果在函数里,要修改传入值,就必须传入指针了,这是他的设计机制决定的..汇编直接修改内存里的值就能达到目的. 从这里也可以看出,汇编占的空间会比C语言小.

       两种方式的比较

         高级语言易懂,写代码更方便.底层语言工作效率更高,但编写效率低.而且C语言学了再用汇编语言写的话,会令人烦躁(属于给自己找理由,如果都会用更好).

         举个例子:变量之间赋值,

        C语言直接写short int b=a;汇编语言写的话,要经过寄存器(规定了内存之间不能直接赋值)

三.指针的实现

        上面不是说过了指针吗?寄存器%rsp始终指向栈首元素,还要能访问栈内其他数据.就是说要实现指针指向一个数据块. 示意图如下:

代码:

//以下非代码,是想在对应地址内插入的数据,
$0x123,0xff00    
$0x456,0xff08
$0x789,0xff10    

//以下是操作代码
leaq 0xff10,%rsp       //栈内第一个元素,压栈是向下增长,所以指向最大的一个位置
movdq $0x789,(%rsp) 
//入栈
subq 8,%rsp            //地址值减8
movq $0x456,(%rsp)     //压入数据
//通常把地址作为第一个操作数更好理解
movq 0xff80,(%rsp)     //把某个地址内的值传到寄存器指向的地址

小结

        汇编语言中数据的传递,和高级语言(C语言)之间有映射关系.

        用move指令表示传值,用leaq指令表示传递地址.----这是约定的写法.

        指针的实现与C语言也非常类似,变量和指针之间有对应关系,指针(非const指针)可以读取变量内数据,也可以被修改.与之对应的,指向某个内存位置的寄存器既可以作为第一个操作数读取该内存地址的数值,也可以作为第二个操作数被写入.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jllws1

你的鼓励是我创作的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值