龙芯下汇编语言编程(2)

时间:2022-01-01 12:22:23

作者: comcat 发表日期: 2007-03-23 20:11   http://comcat.blog.openrays.org/blog.php?do=showone&tid=314

 

1. 判断的实现

看这条C语句的汇编实现:

if(i == j)
f = g + h;
else
f = g - h;

------------------------------------------------------------

bne $15, $16, Else # i!=j,则跳转到Else

add $17, $18, $19 # f=g+h

j Exit # 无条件跳转

Else:
sub $17, $18, $19 # f=g-h

Exit:


2. 小于判断的实现

if(i >= j)
f = g + h;
else
f = g - h;

--------------------------------------------------

slt $9, $15, $16 # i<j则$9=1,否则$9=0
bne $9, $0, Else # $9!=0,则跳转到Else
# 上面两条指令实现了“小于则转移”

add $17, $18, $19 # f=g+h
j Exit # 无条件跳转

Else:
sub $17, $18, $19 # f=g-h

Exit:


另一种实现为:

sub $9, $15, $16 # $9=i-j
bltz $9, Else # $9小于0,则跳转到Else
# 上面两条指令实现了“小于则转移”

add $17, $18, $19 # f=g+h
j Exit # 无条件跳转

Else:
sub $17, $18, $19 # f=g-h

Exit:


3. 更多判断的实现

sub t0, s0, s1 # t0 = s0 - s1 -------- [1]

bgez t0, Else # t0大于等于0,则跳转到Else
#上面两条指令实现了大于等于则转移

bgtz t0, Else # t0大于0,则跳转到Else;与[1]联用,实现大于则跳转

blez t0, Else # t0小于等于0,则跳转到Else;与[1]联用,实现小于等于则跳转
bltz t0, Else # t0小于0,则跳转到Else;与[1]联用,实现小于则跳转
Else:
......

加上前面的 bne, beq 相等和不等的跳转指令,可以实现所有的逻辑判断。



4. 循环的实现

while(s==k)
f = g + h;

----------------------------------

loop:
add t1, s3, s3 # t1 = 2*i
add t1, t1, t1 # t1 = 4*i

add t1, t1, s6 # s的地址置于t1
lw t0, 0(t1) # t0 = s

bne t0, s5, Exit # s != k,则停止循环
add s3, s3, s4 # i = i+j
j loop # 跳至loop
Exit:


5. 完整的例子

.text
.globl main
.ent main
main:
.frame $fp, 32, $31 # 帧指针为$fp,帧大小32,返回寄存器$31
.mask 0xc0000000,-4 # $31, $30保存于28($sp),0xc0000000为需保存之寄存器位图
.set noreorder # 关闭汇编器自动填充延迟槽
.cpload $25 # 汇编伪操作,告诉汇编器根据$25寄存器正确设置gp
.set nomacro

addiu $sp, -32 # 栈空间分配32字节
sw $ra, 24($sp) # 保存返回地址
sw $fp, 20($sp) # 保存帧指针
move $fp, $sp # 帧指针就绪
.cprestore 8 # 汇编器伪操作,保存gp于8($fp)

# 预留传参数的栈空间;printf会直接对栈上预留给参数的空间直接操作
# 会覆盖掉8($fp)处的gp,造成调用失败。
addiu $sp, $sp, -20


li $18, 0x3 # 循环次数为3

lui $8, %hi(msg2) # %hi() 求地址的高16位, %lo()求低16位
addiu $17, $8, %lo(msg2) # $17 中为字符串首地址


loop:
move $4, $17 # printf之第一个参数

lw $25, %got(printf)($28) # 获取printf函数地址
jalr $25 # 调用printf
nop

lw $28, 8($fp) # 从栈回复gp,因为进入printf后gp被改写

addiu $18, $18, -1
bne $18, $0, loop # 不等于0,跳转到前面的loop
nop

move $sp, $fp # 栈指针复位
lw $ra, 24($sp) # 返回地址恢复
lw $fp, 20($sp) # 原帧指针恢复
addu $sp, 32 # 回收栈空间

move $2,$0 # 返回值为0
jr $31 # 返回
nop
.end main

.rdata
msg2:
.asciiz "Hello Baby!\n"