在C:中给出一个非常基本的链表
struct node {
int value;
struct node *next;
};
我想写函数";地图";RISC-V汇编语言。map函数递归地应用一个函数来更改列表中每个节点的值。例如:将链接列表中的所有数据平方。C中的函数供参考:
void map(struct node *head, int (*f)(int))
{
if (!head) { return; }
head->value = f(head->value);
map(head->next,f);
}
测试输出如下:打印链表中的数据,用名为"的函数指针调用map;正方形";它将对每个值求平方,然后再次调用映射到名为"的函数指针;递减";这将使每个值减小1。
9 8 7 6 5 4 3 2 1 0
81 64 49 36 25 16 9 4 1 0
80 63 48 35 24 15 8 3 0 -1
这是我在Venus中运行的RISC-V代码,但是当我尝试调用传递到map中的函数时,第76行出现了问题。
.globl map
.text
main:
jal ra, create_default_list
add s0, a0, x0 # a0 (and now s0) is the head of node list
# Print the list
add a0, s0, x0
jal ra, print_list
# Print a newline
jal ra, print_newline
# === Calling `map(head, &square)` ===
# Load function arguments
add a0, s0, x0 # Loads the address of the first node into a0
# Load the address of the "square" function into a1 (hint: check out "la" on the green sheet)
### YOUR CODE HERE ###
la a1, square
# Issue the call to map
jal ra, map
# Print the squared list
add a0, s0, x0
jal ra, print_list
jal ra, print_newline
# === Calling `map(head, &decrement)` ===
# Because our `map` function modifies the list in-place, the decrement takes place after
# the square does
# Load function arguments
add a0, s0, x0 # Loads the address of the first node into a0
# Load the address of the "decrement" function into a1 (should be very similar to before)
### YOUR CODE HERE ###
# Issue the call to map
jal ra, map
# Print decremented list
add a0, s0, x0
jal ra, print_list
jal ra, print_newline
addi a0, x0, 10
ecall # Terminate the program
map:
# Prologue: Make space on the stack and back-up registers
### YOUR CODE HERE ###
addi sp, sp, -8
sw ra, 4(sp)
sw a0, 0(sp)
beq a0, x0, done # If we were given a null pointer (address 0), we're done.
add s0, a0, x0 # Save address of this node in s0
add s1, a1, x0 # Save address of function in s1
# Remember that each node is 8 bytes long: 4 for the value followed by 4 for the pointer to next.
# What does this tell you about how you access the value and how you access the pointer to next?
# Load the value of the current node into a0
# THINK: Why a0?
### YOUR CODE HERE ###
lw a0, 0(s0)
# Call the function in question on that value. DO NOT use a label (be prepared to answer why).
# Hint: Where do we keep track of the function to call? Recall the parameters of "map".
### YOUR CODE HERE ###
jalr ra, 0(a1)
# Store the returned value back into the node
# Where can you assume the returned value is?
### YOUR CODE HERE ###
sw a0 0(s0)
# Load the address of the next node into a0
# The address of the next node is an attribute of the current node.
# Think about how structs are organized in memory.
### YOUR CODE HERE ###
lw t0 4(s0)
mv a0 t0
# Put the address of the function back into a1 to prepare for the recursion
# THINK: why a1? What about a0?
### YOUR CODE HERE ###
mv a1 s1
# Recurse
### YOUR CODE HERE ###
jal ra, map
lw ra, 4(sp)
lw s0, 0(sp)
addi sp, sp, 8
jr ra
done:
# Epilogue: Restore register values and free space from the stack
### YOUR CODE HERE ###
addi sp, sp, -8
jr ra # Return to caller
# === Definition of the "square" function ===
square:
mul a0, a0, a0
jr ra
# === Definition of the "decrement" function ===
decrement:
addi a0, a0, -1
jr ra
# === Helper functions ===
# You don't need to understand these, but reading them may be useful
create_default_list:
addi sp, sp, -12
sw ra, 0(sp)
sw s0, 4(sp)
sw s1, 8(sp)
li s0, 0 # Pointer to the last node we handled
li s1, 0 # Number of nodes handled
loop: # do...
li a0, 8
jal ra, malloc # Allocate memory for the next node
sw s1, 0(a0) # node->value = i
sw s0, 4(a0) # node->next = last
add s0, a0, x0 # last = node
addi s1, s1, 1 # i++
addi t0, x0, 10
bne s1, t0, loop # ... while i!= 10
lw ra, 0(sp)
lw s0, 4(sp)
lw s1, 8(sp)
addi sp, sp, 12
jr ra
print_list:
bne a0, x0, print_me_and_recurse
jr ra # Nothing to print
print_me_and_recurse:
add t0, a0, x0 # t0 gets current node address
lw a1, 0(t0) # a1 gets value in current node
addi a0, x0, 1 # Prepare for print integer ecall
ecall
addi a1, x0, ' ' # a0 gets address of string containing space
addi a0, x0, 11 # Prepare for print char syscall
ecall
lw a0, 4(t0) # a0 gets address of next node
jal x0, print_list # Recurse. The value of ra hasn't been changed.
print_newline:
addi a1, x0, 'n' # Load in ascii code for newline
addi a0, x0, 11
ecall
jr ra
malloc:
addi a1, a0, 0
addi a0, x0, 9
ecall
jr ra
.data
start_msg: .asciiz "List before: "
end_msg: .asciiz "List after: "
.text
main:
jal ra, create_default_list
add s0, a0, x0 # $v0 = $s0 is head of node list
#print the list
add a0, s0, x0
jal ra, print_list
# print a newline
jal ra, print_newline
# load your args
add a0, s0, x0 # load the address of the first node into $a0
# load the address of the function in question into $a1 (check out la)
### YOUR CODE HERE ###
la a1,square
# issue the call to map
jal ra, map
#print the list
add a0, s0, x0
jal ra, print_list
addi a0, x0, 10
ecall #Terminate the program
map:
# Prologue: Make space on the stack and back-up registers
### YOUR CODE HERE ###
addi sp, sp, -12
sw ra, 0(sp)
sw s0, 4(sp)
sw s1, 8(sp)
beq a0, x0, done # If we were given a null pointer (address 0), we're done.
add s0, a0, x0 # Save address of this node in s0
add s1, a1, x0 # Save address of function in s1
# Remember that each node is 8 bytes long: 4 for the value followed by 4 for the pointer to next.
# What does this tell you about how you access the value and how you access the pointer to next?
# load the value of the current node into a0
# THINK: why a0?
### YOUR CODE HERE ###
lw a0 ,0(s0)
# Call the function in question on that value. DO NOT use a label (be prepared to answer why).
# What function? Recall the parameters of "map"
### YOUR CODE HERE ###
jalr s1
# store the returned value back into the node
# Where can you assume the returned value is?
### YOUR CODE HERE ###
sw a0, 0(s0)
# Load the address of the next node into a0
# The Address of the next node is an attribute of the current node.
# Think about how structs are organized in memory.
### YOUR CODE HERE ###
lw a0, 4(s0)
# Put the address of the function back into a1 to prepare for the recursion
# THINK: why a1? What about a0?
### YOUR CODE HERE ###
add a1, s1, x0
# recurse
### YOUR CODE HERE ###
jal ra map
done:
# Epilogue: Restore register values and free space from the stack
### YOUR CODE HERE ###
addi sp, sp, 12
lw ra, 0(sp)
lw s0, 4(sp)
lw s1, 8(sp)
jr ra # Return to caller
square:
mul a0 ,a0, a0
jr ra
create_default_list:
addi sp, sp, -12
sw ra, 0(sp)
sw s0, 4(sp)
sw s1, 8(sp)
li s0, 0 # pointer to the last node we handled
li s1, 0 # number of nodes handled
loop: #do...
li a0, 8
jal ra, malloc # get memory for the next node
sw s1, 0(a0) # node->value = i
sw s0, 4(a0) # node->next = last
add s0, a0, x0 # last = node
addi s1, s1, 1 # i++
addi t0, x0, 10
bne s1, t0, loop # ... while i!= 10
lw ra, 0(sp)
lw s0, 4(sp)
lw s1, 8(sp)
addi sp, sp, 12
jr ra
print_list:
bne a0, x0, printMeAndRecurse
jr ra # nothing to print
printMeAndRecurse:
add t0, a0, x0 # t0 gets current node address
lw a1, 0(t0) # a1 gets value in current node
addi a0, x0, 1 # prepare for print integer ecall
ecall
addi a1, x0, ' ' # a0 gets address of string containing space
addi a0, x0, 11 # prepare for print string syscall
ecall
lw a0, 4(t0) # a0 gets address of next node
jal x0, print_list # recurse. We don't have to use jal because we already have where we want to return to in ra
print_newline:
addi a1, x0, 'n' # Load in ascii code for newline
addi a0, x0, 11
ecall
jr ra
malloc:
addi a1, a0, 0
addi a0, x0 9
ecall
jr ra