Язык ассемблера не имеет ничего общего с рекурсией, которая просто работает из-за языка C, соглашений о вызовах и реализации.Просто внедрите C в ассемблере и не заботьтесь о рекурсии.Я думаю, что я затронул этот вопрос в проекте для домашних животных http://github.com/dwelch67/lsasim, если только я не изменил его в последнем уроке - ручное преобразование рекурсии в C в ассемблер.Это не работает, так что не стоит беспокоиться о том, что это домашняя задача.
В любом случае, ключом к запуску является простое использование C в сборке.
Например, у вас есть функция с входными параметрами.
int fix(int i, int x)
Вам потребуется объявить себя соглашением о вызовах или использовать существующее, чтобы реализовать C, это означает, что вам нужно некоторое место для входных параметров, либо поместите их в стек, либо внесите в регистры.Предполагая отсутствие оптимизации, вы сохраняете эти переменные по всей функции и очищаете в конце.Поэтому, если вам нужно вызывать ЛЮБУЮ функцию в любом месте кода (рекурсия, вызывающая одну и ту же функцию, является очень маленьким подмножеством ЛЮБОГО, но попадает в эту категорию и НЕ СПЕЦИАЛЬНА), вам необходимо сохранить эти переменные.Если соглашение о вызовах вносит их в стек, то вы уже сделали, если соглашение о вызовах вносит их в регистры, вам нужно сохранить их до вызова и восстановить после
push i
push x
implement call to function
pop x
pop i
и продолжить реализациюfunction.
, то есть все остальное позаботится о себе.
Если вы заметили, что функция, созданная вами в качестве примера, не имеет пути, в котором нужны входные переменныебыть сохраненным после вызова функции внутри этой функции.И входные переменные модифицируются и используются в качестве входных данных для следующего вызова.поэтому оптимизация для вашей реализации кода на C будет заключаться в том, чтобы не беспокоиться о сохранении этих переменных.просто измените их и передайте.Использование регистров в соглашении о вызовах было бы самым простым способом сделать это для этой конкретной функции.Это то, что компилятор будет делать в любом случае при оптимизации (не сохранять при использовании соглашения о вызовах на основе регистров).
Вы также можете выполнить хвостовую оптимизацию, если она так называется.Обычно при вызове функции вы используете все, что обычно делает инструкция, для выполнения «вызова», который отличается от простого перехода или перехода, потому что где-то хранится возвращаемое значение.И есть какая-то функция возврата, которая отменяет это и возвращает обратно к инструкции после вызова.Вложенные вызовы означают вложение возвращаемых значений, отслеживание всех из них.В этом случае, хотя и в других случаях, когда последнее, что вы делаете, путь выполнения функции - это вызов другой функции, вы можете вместо этого (зависит от набора инструкций) перейти к функции и не должны вкладывать другой набор возвращаемых значений.Например, для набора команд постановки на охрану:
Какой-то код вызывает первую функцию:
bl firstfun:
На рукоятке bl означает ответвление.регистр 14 будет заполнен возвращаемым значением, а счетчик программ будет заполнен адресом функции, firstfun.
обычно, если вам нужно вызвать функцию из функции, которую нужно сохранить, r14 такВы можете вернуться из этой функции без этой хвостовой оптимизации:
firstfun:
...
push {r14}
bl secondfun
pop {r14}
bx r14
...
secondfun:
bx r14
bx lr означает переход к содержимому в r14, который в данном случае является возвращением.оптимизация выглядит следующим образом, важно отметить, что в первой функции вызов второй функции - это последнее, что вы делаете перед возвратом из первой функции.это ключ к этой оптимизации.
firstfun:
...
b secondfun
...
secondfun:
bx r14
b просто означает ветвление, а не ветвление, которое просто изменяет ПК и не изменяет r14 или любой другой регистр или стек.Выполнение двух реализаций одинаково функционально, внешняя функция вызывает firstfun, и в правильном пути выполнения есть возврат (bx r14).
Другие люди отметили, что этот код может полностью оптимизировать себя в ничто, так как вы возвращаете ноль первоначальному вызывающему.
fix:
return 0