ARM GCC генерирует функции proog

Я упомянул, что инструментальные средства ARM могут генерировать разные пролог функций. Фактически, я увидел два obj файла (vmlinux) с совершенно разными прологами функций:

Первый случай выглядит так:

push {some registers maybe, fp, lr} (lr ommited in leaf function)

Второй случай выглядит так:

push {some registers maybe, fp, sp, lr, pc} (i can confuse the order)

Так как я вижу, что второй добавляет дополнительно pc и sp. Кроме того, я видел некоторые комментарии в утилите crash (проект kdump), где было указано, что стекный фрейм ядра должен иметь формат {..., fp, sp, lr, pc}, что путают меня больше, потому что я вижу, что в некоторых случаях это не правда.

1.) Как я понял, что некоторые дополнительные gcc-флаги необходимы для толкания дополнительно pc и sp в функции proog? Если да, то каковы они?

2.) Для чего это используется? В принципе, поскольку я понимаю, что могу разматывать стек только с FP и LR, зачем мне эти дополнительные значения?

3.) Если это ничего не болит с флагами компиляции - как я могу заставить генерацию этой расширенной функции пролога и снова в чем цель?

Спасибо.

Ответ 1

1.) Как я понял, что некоторые дополнительные gcc-флаги необходимы для толкания дополнительно pc и sp в функции proog? Если да, то каковы они?

Существует много опций gcc, которые влияют на фреймы стека (-march, -mtune и т.д. могут влиять на инструкции, используемые для примера). В вашем случае это было -mapcs-frame. Кроме того, -fomit-frame-pointer удалит кадры из функций листа. Несколько статических функций могут быть объединены вместе в одну сгенерированную функцию, что дополнительно уменьшает количество кадров. APCS может вызвать несколько более медленный код, но необходим для трассировки стека.

2.) Для чего это используется? В принципе, поскольку я понимаю, что могу разматывать стек только с FP и LR, зачем мне эти дополнительные значения?

Все регистры, которые не являются параметрами (r0-r3), должны быть сохранены, поскольку они должны быть восстановлены при возврате вызывающему абоненту. Компилятор будет выделять дополнительные локали в стеке, поэтому sp будет почти всегда изменяться при изменении fp. Почему хранится pc, см. Ниже.

3.) Если это ничего не болит с флагами компиляции - как я могу заставить генерацию этой расширенной функции пролога и снова в чем цель?

Это флагов компилятора, как вы уже догадались.

; Prologue - setup
mov     ip, sp                 ; get a copy of sp.
stm     sp!, {fp, ip, lr, pc}  ; Save the frame on the stack. See Addendum
sub     fp, ip, #4             ; Set the new frame pointer.
    ...
; Epilogue - return
ldm     sp, {fp, sp, lr}       ; restore stack, frame pointer and old link.
    ...                        ; maybe more stuff here.
bx      lr                     ; return.

Типичное сохранение stm sp!, {fp, ip, lr, pc} и восстановление ldm sp, {fp, sp, lr}. Это правильно, если вы изучите документы ABI/APCS. Обратите внимание, что нет! попытаться исправить стек. Он загружается явно из сохраненного значения ip.

Кроме того, сохраненный pc не используется в эпилоге. Это просто отброшенные данные в стеке. Так зачем это делать? Обработчики исключений (прерывания, сигналы или исключения С++) и другие механизмы трассировки стека хотят знать, кто сохранил фрейм. ARM всегда имеет только один пролог функции (одна точка входа). Однако есть несколько выходов. В некоторых случаях возврат, подобный return function();, может фактически превратиться в b function в, возможно, больше материала. Это называется хвостом. Также, когда функция листьев вызывается в середине процедуры и возникает исключение, она увидит диапазон листа pc, но на листе не может быть кадра вызова. Сохраняя pc, кадр вызова может быть проверен, когда в листке появляется исключение, чтобы узнать, кто действительно сохранил стек. Таблицы pc по сравнению с деструктором и т.д., Возможно, хранятся, чтобы позволить освободить объекты или выяснить, как вызвать обработчик сигнала. Дополнительный pc просто приятен при трассировке стека, и операция почти свободна из-за подкладки труб.

Смотрите также: ARM Link and frame register вопрос о том, как компилятор использует эти регистры.