如何获取数组的地址并将其保存到汇编中的寄存器?
How to get the address of an array and save it to a register in assembly?
我想将 A[ ] 的内存地址保存在一个寄存器中,比如 $a0 因为即使我可以在程序的任何范围内访问 A,我也会将其作为参数传递给过程。
在代码中,我使用 sb
而不是 sw
的原因是当我 assemble 它时存在对齐问题。
当我说 lb $a0, A
时,它将 4
存储到 $a0
,这是值而不是地址。
.data
A: .space 16
.globl main
main:
# Initialize values in the array
addi $s0, $zero, 4
addi $s1, $zero, 8
addi $s2, $zero, 3
addi $s3, $zero, 5
# This $t0 is just used for indexing while inserting to A
addi $t0, $zero, 0
sb $s0, A($t0)
addi $t0, $t0, 4
sb $s1, A($t0)
addi $t0, $t0, 4
sb $s2, A($t0)
addi $t0, $t0, 4
sb $s3, A($t0)
li $t0, 0
使用la
伪指令。 la $t0, A
.
如果 A
不适合 16 位,这将 assemble 到像
这样的序列
lui $t0, high16(A)
; ori $t0, $zero, low16(A)
。参见 this basic MIPS instruction-set reference for LUI。您的 assembler 可能会使用 addui
而不是 ori
;我认为一些 assemble 用户有一个选项可以选择 li
/ la
伪指令。
还有一个 li
伪指令(用于立即加载)用于数字常量而不是地址,但它的工作原理相同。
对于对齐问题,请尝试确保 A
的地址是字对齐的。我原以为这会自动发生,但也许您在之前发布的代码 .data
中遗漏了一个 .asciz
字符串常量?无论如何,要么将 A
首先放在非 4 的倍数大小的对象之前,要么使用 .align
指令填充到下一个 4 的倍数。
.data
.align 4 # align by 4 bytes.
A: .space 16
如果A
的地址适合16位,你不需要它或寄存器中的偏移量,只需使用sb $s0, A+4($zero)
等等。 (但是如果你使用的是 sb / lb,那为什么元素之间还要偏移 4 个字节?为什么不把它做成一个 4 字节长的 4 字节数组?)
.globl main
main:
# Initialize values in the array
li $t0, 4
sw $t0, A($zero)
addui $t0, $zero, 8 # doing it manually without an LI pseudo-instruction
sw $t0, A+4($zero)
li $t0, 3
sw $t0, A+8($zero)
li $t0, 5
sw $t0, A+12($zero)
#li $t0, 0
你不需要每次都使用不同的寄存器,虽然我猜想没有寄存器重命名 a classic-RISC pipeline might stall for a Write-After-Read hazard (WAR) 当 li
试图在前一个 [=31] 之前写 t0
=] 读过它。在超标量 CPU 上,混合不同的指令类型(ALU addui
和内存 sw
)是有意义的,这样它们就可以并行执行,而不是在第一个存储执行之前可能等待更长的时间.
此外,这可以说更易读,因为值和地址放在一起。
我想将 A[ ] 的内存地址保存在一个寄存器中,比如 $a0 因为即使我可以在程序的任何范围内访问 A,我也会将其作为参数传递给过程。
在代码中,我使用 sb
而不是 sw
的原因是当我 assemble 它时存在对齐问题。
当我说 lb $a0, A
时,它将 4
存储到 $a0
,这是值而不是地址。
.data
A: .space 16
.globl main
main:
# Initialize values in the array
addi $s0, $zero, 4
addi $s1, $zero, 8
addi $s2, $zero, 3
addi $s3, $zero, 5
# This $t0 is just used for indexing while inserting to A
addi $t0, $zero, 0
sb $s0, A($t0)
addi $t0, $t0, 4
sb $s1, A($t0)
addi $t0, $t0, 4
sb $s2, A($t0)
addi $t0, $t0, 4
sb $s3, A($t0)
li $t0, 0
使用la
伪指令。 la $t0, A
.
如果 A
不适合 16 位,这将 assemble 到像
这样的序列
lui $t0, high16(A)
; ori $t0, $zero, low16(A)
。参见 this basic MIPS instruction-set reference for LUI。您的 assembler 可能会使用 addui
而不是 ori
;我认为一些 assemble 用户有一个选项可以选择 li
/ la
伪指令。
还有一个 li
伪指令(用于立即加载)用于数字常量而不是地址,但它的工作原理相同。
对于对齐问题,请尝试确保 A
的地址是字对齐的。我原以为这会自动发生,但也许您在之前发布的代码 .data
中遗漏了一个 .asciz
字符串常量?无论如何,要么将 A
首先放在非 4 的倍数大小的对象之前,要么使用 .align
指令填充到下一个 4 的倍数。
.data
.align 4 # align by 4 bytes.
A: .space 16
如果A
的地址适合16位,你不需要它或寄存器中的偏移量,只需使用sb $s0, A+4($zero)
等等。 (但是如果你使用的是 sb / lb,那为什么元素之间还要偏移 4 个字节?为什么不把它做成一个 4 字节长的 4 字节数组?)
.globl main
main:
# Initialize values in the array
li $t0, 4
sw $t0, A($zero)
addui $t0, $zero, 8 # doing it manually without an LI pseudo-instruction
sw $t0, A+4($zero)
li $t0, 3
sw $t0, A+8($zero)
li $t0, 5
sw $t0, A+12($zero)
#li $t0, 0
你不需要每次都使用不同的寄存器,虽然我猜想没有寄存器重命名 a classic-RISC pipeline might stall for a Write-After-Read hazard (WAR) 当 li
试图在前一个 [=31] 之前写 t0
=] 读过它。在超标量 CPU 上,混合不同的指令类型(ALU addui
和内存 sw
)是有意义的,这样它们就可以并行执行,而不是在第一个存储执行之前可能等待更长的时间.
此外,这可以说更易读,因为值和地址放在一起。