计算机系统基础-学习记录6

程序的机器级表示:过程(续)

寄存器存储惯例

  调用者保存暂存的值在调用者的帧内
  被调用者保存暂存的值在被调用者的帧内

  对于调用者而言

  %rax用于保存返回值
  六个寄存器%rdi,%rsi,%rdx,%rcx,%r8,%r9用于保存参数
  超过6个参数后,多出的参数将会通过栈进行传递

  调用者需要保存%r10和%r11两个寄存器,之后会用到

  对于被调用者而言

  被调用者保存4个寄存器:%rbx,%r12,%r13,%r14

  被调用者也保存%rbp(帧指针)(返回时返还)、%rsp(栈指针,由被调用者保存)(用完后恢复原来的值)

  关于被调用者和调用者使用寄存器的情况举例

  依旧是下述C语言指令:

long call_incr2(long x) {
    long v1 = 15213;
    long v2 = incr(&v1, 3000);
    return x+v2;
}

  其对应的汇编代码为:

call_incr2:
  pushq   %rbx
  subq    $16, %rsp
  movq    %rdi, %rbx
  movq    $15213, 8(%rsp)
  movl    $3000, %esi
  leaq    8(%rsp), %rdi
  call    incr
  addq    %rbx, %rax
  addq    $16, %rsp
  popq    %rbx
  ret

  关于这段代码的分行叙述(个人理解,不一定对):
  1、在调用call_incr2时,%rbx可能是调用者正在使用的寄存器,而现在,被调用者call_incr2却打算用到这个寄存器。因此,先对%rbx进行进栈操作
  2、栈指针下移两个字节,给接下来的存储(帧)留下空间
  3、将调用者的%rdi的值(传入到call_incr2函数中的实参),赋给被调用者(call_incr2)%rbx,此时%rbx存储了x值
  4、将局部变量v1=15213放入此过程的帧中,其地址紧接刚才被压入栈中的%rbx
  5、call_incr2作为incr的调用者,将准备传递的第二个实参3000赋值给寄存器%rsi
  6、将%rsp上移8个字节的地址赋给作为调用者使用的寄存器%rdi,意图在于将准备传递的第一个实参&v1(v1的地址)赋值给寄存器%rdi。注意到这两个要传递的参数都被存入了调用者寄存器,以及%rsp+8这个地址上存储了v1
  7、调用incr过程
  8、调用完成后,%rax存储的是incr返回的值,即v2。现在,用v2加上%rbx存储的x,即返回值变为v2+x,此时,主要运算便完成了
  9、还原栈指针,将刚才暂时放在call_incr2帧中的常数15213抹去,因为不再需要它了
  10、弹出之前的%rbx的值,恢复%rbx在刚开始调用call_incr2时的状态,这样一来,在返回后,call_incr2的调用者传入的实参就不会被改变

  有的过程不需要帧,因为不需要保存

递归

  递归是以栈实现的,没有栈,就无法支持递归

  和过程一样,递归在返回时,也是以寄存器%rax返回的

  递归的汇编语言举例

  有下述计算x的二进制码中1的总数的C语言程序:

/* Recursive popcount */
long pcount_r(unsigned long x) {
  if (x == 0)
    return 0;
  else
    return (x & 1) 
           + pcount_r(x >> 1);
}

  对应的汇编语言为:

pcount_r:
  movl    $0, %eax
  testq   %rdi, %rdi
  je      .L6
  pushq   %rbx
  movq    %rdi, %rbx
  andl    $1, %ebx
  shrq    %rdi
  call    pcount_r
  addq    %rbx, %rax
  popq    %rbx
.L6:
  rep; ret

  现以输入x=1011 2 _2 2为例,描述此情形下的递归全过程:

  1、初始时刻,栈指针指向栈中某个位置,寄存器%rdi存放着输入的x值:1011 2 _2 2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XZIWIJR5-1603631664346)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025202831334.png)]

  2、数值0被放入到寄存器%rax中(初始化),随后判断%rdi是否为空(为0)。此时%rdi=1011,所以判断不为空,ZF=0,je处不跳转

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ukwl6B32-1603631664350)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025203316936.png)]

  3、将寄存器%rbx压入栈中,对当前的值进行保存。注意,在此次分析中,现在并不知道%rbx存的值是多少,个人感觉它可能是初始值(或者是调用者的某个值)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ygEjdYef-1603631664352)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025203707411.png)]

  4、%rdi的值赋给%rbx

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sdLCBC19-1603631664356)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025203749983.png)]

  5、%rbx和常数1进行按位与运算,得到1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sLBswLao-1603631664358)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025204049234.png)]

  6、%rdi向右逻辑移位1次,得101

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QYI5QD4t-1603631664363)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025204211426.png)]

  7、调用自身。先将过程结束后,addq那一行的地址压入栈中,再跳转回到pcount_r开始处

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y9aBG5dn-1603631664364)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025204418483.png)]

  8、与第一次同理。先将%rax置0,再检验%rdi是否为0,结果为非0,je不执行。随后%rbx=0001被压入栈中以进行保存,再将%rdi的值赋给%rbx。%rbx与1进行按位与运算,得到%rbx=0001。最后再将%rdi右移,得到%rdi=10,随后进入下一次对自身的调用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a0mAvHwE-1603631664366)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025204807281.png)]

  9、经过同样的流程,完成第二次对自身的调用:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KEbfblSk-1603631664367)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025205002414.png)]

  10、经过同样的流程,完成第三次对自身的调用。注意到进入第四次调用时,%rdi的值变为0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QoMGPC2C-1603631664369)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025205540610.png)]

  11、第四次调用时,判断%rdi的结果为0,因此直接跳转至L6处,进行了返回。此时,从栈中弹出第三次调用的addq地址,并移动到那个地方

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TpuWhsSW-1603631664370)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025205916940.png)]

  12、执行addq语句,将%rbx的值加到%rax上,得%rax=1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t4RbgRxa-1603631664372)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025210058016.png)]

  13、从栈中弹出%rbx,恢复%rbx之前存入栈中的值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zXy7lsih-1603631664373)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025210152420.png)]

  14、返回后,又回到上一级的addq处,运算同理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Av0xBp3G-1603631664375)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025210330265.png)]

  15、再返回一级:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YDGfp0DC-1603631664378)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025210402535.png)]

  16、最后一级返回后,%rbx恢复到最开始时的值,而%rax则是最终的返回值,11 2 _2 2,即十进制的3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kYvOzFYw-1603631664379)(C:\Users\蔡三圈\AppData\Roaming\Typora\typora-user-images\image-20201025210454506.png)]

无论是哪种高级语言,实现的过程调用都是一样的

程序的机器级表示:特殊数据结构

  目前已经知道了基本数据类型的底层表示方法:

  字符:ASCII
  整数:unsigned、signed(所有有符号数使用二进制补码表示)
  浮点数:float(单精度,32位)、double(双精度,64位)、80位(仅Intel)

  但特殊的数据结构在底层如何表示?

数组

  将同类型的数据放在一起

  占用连续的空间

一维数组

  从首地址开始,每个元素都占用相同的空间,因此下标为k的元素地址的计算方式为:首地址+每个元素所占空间大小*元素的下标k

多维数组

  二维数组的存储方式:
  C语言——按行优先(从第0行开始,一行一行地存)
  Java——按列优先

  多级数组:数组中存储地址,每个地址指向一个数组

  利用指针可以实现动态数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值