Использование сохраненных регистров в основной функции на ассемблере RISC-V

Предположим, что следующая простая основная функция написана на языке RISC-V Assembly:

.globl main
main:
     addi s3,zero,10 #Should this register (s3) be saved before using?

Поскольку s3 — это сохраненный регистр, следует соблюдать соглашения о вызове процедур, и, следовательно, этот регистр должен быть помещен в стек перед его использованием. Однако, глядя на исходный файл, можно увидеть, что никакая другая процедура не использовала этот регистр, и сохранение регистра в стеке кажется излишним.

Мой вопрос: следует ли сохранять регистры этих типов каждый раз перед каждым использованием, даже если это означает написание дополнительного (избыточного) кода только для соблюдения соглашений о вызовах? Можно ли иногда игнорировать эти соглашения для повышения производительности?

В приведенном выше примере следует ли сохранять регистр, потому что неизвестно, использовал ли главный вызывающий регистр s3?

Да, их нужно сохранять каждый раз, даже если для этого потребуется больше кода. Да, вызывающий main (например, код инициализации libc) может использовать s3 для своих собственных целей.   —  person zach    schedule 11.06.2021

См. также:  Ошибка сегментации при вызове функции сборки x86 из программы C
Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 1
  1. zach

    Да, main — это функция, у которой есть реальный вызывающий объект, к которому вы возвращаетесь, и этот вызывающий объект может использовать s3 для чего-то.

    Если ваш main никогда не возвращается, будь то бесконечный цикл или выход только путем вызова exit или системного вызова. Если вы никогда не вернетесь, вам не нужно иметь возможность восстановить состояние вызывающего абонента или даже найти обратный путь (через обратный адрес).

    Так что, если так же удобно вызывать exit вместо того, чтобы когда-либо возвращаться из main, это позволяет вам ничего не сохранять.

    Это также применимо в тех случаях, когда main, конечно, не к чему возвращаться, поэтому возвращение даже не было вариантом. например если это точка входа в ядро ​​или другой автономный код.


    Кроме того, я надеюсь, вы понимаете, что сохранять каждый раз перед каждым использованием означает один раз для каждой функции, которая их использует, а не отдельно для каждого отдельного блока. И не сохраняет регистры, подвергшиеся затиранию вызовов, вокруг каждого вызова функции; просто дай им умереть.

    Можно ли иногда игнорировать эти соглашения для повышения производительности?

    Да, если вы сделаете детали невидимыми для кода, который вы не контролируете.

    Если вы относитесь к небольшим частным вспомогательным функциям как к части одной большой функции, тогда они могут использовать частное пользовательское соглашение о вызовах. (Даже если вы действительно вызываете / возвращаетесь, а не просто переходите к ним, если вы хотите избежать встраивания их в несколько сайтов вызова)

    Иногда это просто использование дополнительных гарантий, когда вы знаете о вызываемой функции. например что он на самом деле не сбивает некоторые из регистров входных аргументов. Это может быть полезно в рекурсии, когда вы вызываете себя: foo(int *p, int a) самостоятельные вызовы могут использовать p, все еще находящиеся в том же регистре без изменений, вместо того, чтобы сохранять p где-то еще для использования после возврата вызова, как при вызове неизвестного функция, в которой вы не можете предположить, что соглашение о вызовах не гарантирует.

    Или, если у вас есть общедоступная оболочка перед вашей реальной частной рекурсивной функцией, вы можете настроить некоторые константы или даже заставить рекурсивную функцию обрабатывать один регистр как статическую переменную вместо передачи указателей на какое-либо общее состояние в объем памяти. (Это уже не чистая рекурсия, а просто цикл, который использует стек asm для отслеживания некоторой истории, которая включает адрес перехода.)

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: