retpseudo

ret

pseudo
Assembly RISC-V Referência

lyszt.net aborda ret e outras instruções RISC-V com mais detalhes.

Descrição

ret retorna de uma função e devolve o controle ao chamador. Um call espera um. Quando uma função é chamada, o chamador coloca um endereço de retorno no registrador ra (veja call e jal), e ret salta para esse endereço, que continua logo após a chamada original. É uma pseudoinstrução que salta para ra.

ret só funciona quando ra ainda contém o endereço correto. Em uma função que não chama nada mais, nada altera ra entre a entrada e a saída. Um call dentro da função sobrescreve ra com um novo endereço de retorno e apaga aquele de que a função precisa. Uma função que chama outras salva seu ra na entrada e o restaura antes do ret. Sem a restauração, a função retorna ao lugar errado, e o programa salta para código não relacionado ou entra em loop infinito.

Por convenção, uma função coloca seu resultado no registrador a0 antes de retornar, e o chamador o lê ali.

O manual do RISC-V diz que um retorno de procedimento na convenção de chamada padrão é codificado como um jalr com rd=x0, rs1=x1 e um imediato de 0. Ele salta para o endereço em x1 e não escreve nenhum endereço de link, já que x0 o descarta. O manual acrescenta que os processadores usam os números de registrador em jal e jalr como dicas para prever retornos de função, o que é uma das razões pelas quais a convenção padrão mantém o endereço de retorno em x1.

O exemplo é a função completa mais simples. square multiplica seu argumento por ele mesmo e ret retorna o resultado. Ela não chama nada mais, então não salva nem restaura nada. Executá-la no simulador mostra o controle saltando de volta para o chamador.

Expande para

jalr zero, ra, 0

O montador substitui esta pseudoinstrução pela instrução ou instruções reais listadas acima.

Exemplo

square:
  mul a0, a0, a0
  ret              # return to the caller