Uso do ponteiro de quadro MIPS
Pergunta
preciso converter meu código do ponteiro de pilha para usar apenas o ponteiro de quadro, como posso fazer isso?eu sou muito novo no MIPS.
eu tenho esse código C de recursão e seu código MIPS abaixo.estou usando o ponteiro de pilha, como posso alterá-lo para usar o ponteiro do quadro?
aqui está meu código C
int fact(int n)
{
if(n!=1)
return n*factorial(n-1);
}
int comb (int n, int k)
{
return fact (n) / fact (k) / fact (n - k);
}
aqui meu código MIPS
comb:
sub $sp, $sp, 16
sw $ra , 0($sp)
sw $s0, 4($sp)
sw $a0, 8($sp)
sw $a1, 12($sp)
jal fact
move $s0, $v0
lw $a0, 12($sp)
jal fact
div $s0, $s0, $v0
lw $a0, 8($sp)
lw $a1, 12($sp)
sub $a0, $a0, $a1
jal fact
div $s0, $s0, $v0
move $v0, $s0
lw $ra, 0($sp)
lw $s0, 4($sp)
addi $sp, $sp, 16
jr $ra
Solução
Achei os comentários de @markgz interessantes.Seu link para a Wikipedia inclui a citação:
O ponteiro de quadro ($30) é opcional e na prática raramente usado, exceto quando a alocação de pilha em uma função é determinada em tempo de execução, por exemplo, chamando alloca().
Eu sempre pensei isso $fp
parecia supérfluo, mas sempre usei mesmo assim porque foi assim que fui ensinado a fazer.
De qualquer forma, se você ainda estiver interessado, aqui está como usei o ponteiro de quadro:
#save $ra $s0, $a0 on stack
addi $sp $sp -4
sw $fp 0($sp)
move $fp $sp
addi $sp $sp -12
sw $ra -4($fp)
sw $a0 -8($fp)
sw $s0 -12($fp)
...
#restore and shrink stack
lw $s0 -12($fp)
lw $ra -4($fp)
lw $fp 0($fp)
addi $sp $sp 16
jr $ra
Portanto, cada vez que a pilha é expandida, eu uso o ponteiro de pilha para salvar o valor antigo do ponteiro do quadro e, em seguida, restauro o valor antigo do ponteiro do quadro ao reduzir a pilha.
Geralmente, apenas copio e colo esse código toda vez que escrevo uma nova função.
Outras dicas
Você deve nunca converter o código MIPS para usar o Ponteiro de quadro em vez do Stack Pointer, porque isso violaria o MIPS Convenção de chamada, e seu código deixaria de funcionar com o código de outras pessoas.
O Frame Pointer normalmente não é usado em assembler MIPS codificado manualmente, porque o ponteiro de pilha não altera o valor durante a execução de uma função.Na verdade, seu próprio código é codificado corretamente para que o ponteiro da pilha nunca mude de valor.
Expandindo a resposta de Konrad Lindenbach:
#save $ra, $s0, $a0, $a1
addi $sp, $sp, -4
sw $fp, 0($sp)
move $fp, $sp
addi $sp, $sp, -16
sw $ra, -4($fp)
sw $a0, -8($fp)
sw $a1, -12($fp)
sw $s0, -16($fp)
#Your Code Here
#Restore
lw $s0, -16($fp)
lw $ra, -4($fp) #Can Be C+P'd from here down
addi $sp, $fp, 4
lw $fp, 0($fp)
ja $ra
Dessa forma, é muito mais fácil ler e escrever sem sacrificar o comprimento das instruções.Você também usaria esse método para alocação dinâmica de memória, pois o snippet de restauração não precisa saber quantos dados foram alocados para a pilha.