Skip to content

2.4

:material-circle-edit-outline: 约 412 个字 :fontawesome-solid-code: 27 行代码 :material-clock-time-two-outline: 预计阅读时间 2 分钟

Procedures

汇编语言的程序编写

Procedure Call Instructions

  • Instruction for procedures: jal ( jump-and-link )
    • Address of following instruction put in x1
    • Jumps to target address
jal x1, ProcedureAddress;Caller 
  • Procedure return: jalr (jump and link register)
    • Like jal, but jumps to 0 + address in x1
    • Use x0 asrd (x0 cannot be changed)
    • Can also be used for computed jumps
jalr x0, 0(x1);Callee

Stack

  • Registers for procedure calling
    • a0 ~ a7(x10-x17): eight argument registers to pass parameters & return values
    • ra/x1:one return address register to return to origin point
      • 上面的caller就是用这个
  • Stack grow from higher address to lower address
    • 约定起始位置在高位,往低位扩张
    • Push: \(sp= sp - 8\) addi sp,sp,-8; sd …,8(sp);
    • Pop: \(sp = sp + 8\) ld …,8(sp); addi sp,sp,8;
      • 8 是字长
    • Stack pointer sp

image-20240326194338299

image-20240326194504182

叶程序不会再调用别的函数

红虚线内是运算部分,和栈无关

将数据放入堆栈的好处是可以临时释放寄存器给运算过程使用

t0 ~ t6和s0 ~ s11是同名标记,是人为规定的,前者不需要保存,后者需要保存

image-20240507211809639

保护现场的事情是被调用者callee负责的,就是保存这些寄存器里面的数据,被调用时首先进行保存,运行结束后还给caller

调用程序的人有权利保护t0~t6,只要它觉得重要,当然这个不是必须的

  • 可以加一个Frame pointer fp ,指向栈的基地址,用于检索不同的栈

Nested Procedures

嵌套程序,以求阶乘函数为例:

int fact ( int n )
{
    if ( n < 1 ) return ( 1 ) ;
    else return ( n * fact ( n - 1 ) ) ;
} 
#n in a0, res in a0
fact:
    addi sp, sp, -16     # adjust stack for 2 items
    sd ra, 8(sp)         # save the return address: x1
    sd a0, 0(sp)         # save the argument n: x10
    addi t0, a0, -1      # x5 = n - 1
    bge t0, zero, L1     # if n >= 1, go to L1 (else)
    addi a0, zero, 1     # return 1 if n < 1
    addi sp, sp, 16      # Recover sp (Why not recover x1 and x10?)
    jalr zero, 0(ra)     # return to caller

L1:
    addi a0, a0, -1      # n >= 1: argument gets (n - 1)
    jal ra, fact         # call fact with (n - 1)
    add t1, a0, zero     # move result of fact(n - 1) to x6 (t1)
    ld a0, 0(sp)         # return from jal: restore argument n
    ld ra, 8(sp)         # restore the return address
    add sp, sp, 16       # adjust stack pointer to pop 2 items
    mul a0, a0, t1       # return n * fact(n - 1)
    jalr zero, 0(ra)     # return to the caller

Memory Layout

一个程序在内存中是这样的

image-20240507213657982

左边一串二进制是地址

  • Text 存放所有的指令代码,PC从Text开始执行一条条指令
  • Static data: global variables
  • Dynamic data: heap
  • Stack: automatic storage
    • 这就是为什么stack是从高位往低位扩展