Листовые функции в SPARC и HP-UX


Я как раз читал статью Phrack, в которой была разборка в HP-UX. Я читал, что есть два класса функций, которые возможны под HP-UX и SPARC; листовые и нелистовые функции. Ниже приведен раздел разборки, который я взял из здесь .

(gdb) disass leaf
Dump of assembler code for function foo:
0x3280 <leaf>:           copy r3,r1
0x3284 <leaf+4>:         copy sp,r3
0x3288 <leaf+8>:         stw,ma r1,40(sr0,sp)
0x328c <leaf+12>:        stw r26,-24(sr0,r3)
0x3290 <leaf+16>:        stw  r0,8(sr0,r3)
0x3294 <leaf+20>:        ldi 1,r19
0x3298 <leaf+24>:        stw  r19,8(sr0,r3)
0x329c <leaf+28>:        ldo 40(r3),sp
0x32a0 <leaf+32>:        ldw,mb -40(sr0,sp),r3
0x32a4 <leaf+36>:        bv,n r0(rp)
End of assembler dump.
(gdb)
Обычно при вызове функции адрес возврата помещается в стек, чтобы программа знала, куда вернуть элемент управления после завершения выполнения функции. Как это работает в случай этих листовых функций?

У меня нет доступа к машинам HP-UX/SPARC, поэтому у меня нет возможности попробовать это самостоятельно(и я не очень хорошо понимаю сборку в этом случае, по той же причине).

Может ли кто-нибудь объяснить, как управление возвращается к вызываемой функции в этом случае?

1 2

1 ответ:

Во-первых, документ, на который вы ссылаетесь, и код, который вы показываете, не Sparc, а PA-RISC, который является отличной архитектурой. Насколько мне известно, не существует версии HP/UX, которая работает на системах, основанных на Sparc.

Тем не менее, точка зрения о листовых функциях аналогична во многих архитектурах, включая Sparc, PA-RISC, PowerPC, ARM, MIPS... фактически все архитектуры RISC. Для всех из них код операции, который выполняет вызов функции, не сохраняет обратный адрес в стеке; на самом деле, не существует никакого "реального" стека, известного аппаратным обеспечением. Вместо этого существует только программное Соглашение для использования конкретного регистра в качестве указателя стека. Вызывающий код операции сохраняет возвращенный адрес в определенном регистре, обычно называемом "регистром ссылок". Код операции для возврата из функции просто считывает этот регистр.

Если сама функция (назовем ее A) вызывает другую функцию (B), то этот вложенный вызов также будет использовать регистр ссылок; однако A потребуется содержимое ссылки зарегистрируйте, когда он вернется. Поэтому a должен сохранять регистр ссылок где-то, обычно в памяти, а точнее в области памяти, обычно используемой как "стек".

Листовая функция-это функция, которая не вызывает никакой другой функции; она просто выполняет свою работу и возвращает. Функция leaf не должна сохранять регистр ссылок в стеке, так как ничто не изменит содержимое регистра ссылок.

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