Как НЕ использовать стек с вызовом функции в GCC? - PullRequest
2 голосов
/ 11 октября 2011

Вот контекст для моего вопроса:

  • Я использую архитектуру ARM7 (ARM720T TDMI ...)
  • Компиляция с использованием GCC CodeSourcedy (arm-none-eabi ver 4.5.2)
  • Я новичок в архитектуре gcc и ARM, но работаю в embeded в течение 5 лет; -)

В моем проекте функция C вызывается изфайл сборки до инициализации стека.Поскольку стек не инициализирован, функция не должна использовать стек.

Возможно ли с помощью некоторой команды "like pragma like" заставить gcc не использовать стек с этой конкретной функцией?

Дополнительная информация: Цель моей работы - преобразовать проект, предварительно скомпилированный с помощью ARMASM, в gcc.Таким образом, в ARMASM, вызывая эту функцию C до начала инициализации стека.Возможно, что окончательным ответом будет то, что это невозможно сделать в gcc ...

Ниже приведен фрагмент списка ELF для функции C, вызываемой в коде сборки (как вы можете видеть, япробовал Always_inline, но при вызове из сборки этого кажется недостаточно):

000049d0 <CInit_Init>:
__attribute__((always_inline)) extern void CInit_Init(void) {
49d0:   e52db004    push    {fp}        ; (str fp, [sp, #-4]!)
49d4:   e28db000    add fp, sp, #0

__attribute__((always_inline)) void COM1_Init(void);

__attribute__((always_inline)) extern inline void COM1_Init_I(void) {
// Skip if already enabled
if (TEST_BIT_CLR(HwrSysControl1, HwSysControl1UartEnable)) {
49d8:   e59f3038    ldr r3, [pc, #56]   ; 4a18 <CInit_Init+0x48>
49dc:   e5933000    ldr r3, [r3]
49e0:   e2033c01    and r3, r3, #256    ; 0x100
49e4:   e3530000    cmp r3, #0
49e8:   1a000007    bne 4a0c <CInit_Init+0x3c>
    HwrUart1Control = (
49ec:   e59f3028    ldr r3, [pc, #40]   ; 4a1c <CInit_Init+0x4c>
49f0:   e59f2028    ldr r2, [pc, #40]   ; 4a20 <CInit_Init+0x50>
49f4:   e5832000    str r2, [r3]
            HwUartControlDataLength8|
            HwUartControlFifoEnable|
            HwUartControlRate115200);
    BIT_SET(HwrSysControl1, HwSysControl1UartEnable);
49f8:   e59f3018    ldr r3, [pc, #24]   ; 4a18 <CInit_Init+0x48>
49fc:   e59f2014    ldr r2, [pc, #20]   ; 4a18 <CInit_Init+0x48>
4a00:   e5922000    ldr r2, [r2]
4a04:   e3822c01    orr r2, r2, #256    ; 0x100
4a08:   e5832000    str r2, [r3]

COM1_Init_I();
}
4a0c:   e28bd000    add sp, fp, #0
4a10:   e49db004    pop {fp}        ; (ldr fp, [sp], #4)
4a14:   e12fff1e    bx  lr
4a18:   80000100    .word   0x80000100
4a1c:   800004c0    .word   0x800004c0
4a20:   00070001    .word   0x00070001

Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 12 октября 2011

просто настроить стек.В противном случае, если вы не хотите, чтобы в стеке не было локальных переменных и было достаточно мало кода, чтобы вы не исчерпали регистры, не вызывайте никаких функций из этой функции и т. Д. Если вам действительно нужны переменные, используйте глобальные переменные.Компилятор НЕ МОЖЕТ генерировать ваш код без использования стека, если вы заставите код исчерпать регистры и глобальные переменные.Ни один переключатель компилятора не будет изобретать хранилище, и я бы не стал доверять компилятору, у которого есть нестандартный прием, не связанный со стеком, который он мог бы попытаться использовать.

Простой, без локальных переменных, даже не требуется промежуточный регистр:

unsigned int fun ( unsigned int a, unsigned int b )
{
    return(a+b);
}

нет стека:

00000000 <fun>:
   0:   e0810000    add r0, r1, r0
   4:   e12fff1e    bx  lr

вы всегда можете изменить стек после вызова исходного кода C, для установки стека перед вызовом C требуется одна-несколько инструкций,просто установите указатель стека.Вам не нужны все указатели стека, только один.либо установите указатель стека, либо напишите функцию на ассемблере, а не на C. Вы все равно должны инициализировать стек перед com-портом.Это одна инструкция, два слова местоположения, и вы звоните C, поэтому стоимость ничтожна.

.globl _start
_start:
    b reset
reset:
        ldr sp,=0x20008000
        bl more_fun
        b .

.globl fun
fun:
    bx lr

.globl fun_out
fun_out:
    bx lr



unsigned int fun ( unsigned int , unsigned int );
void fun_out ( unsigned int, unsigned int, unsigned int, unsigned int );
unsigned int more_fun ( unsigned int a, unsigned int b, unsigned int c )
{
    unsigned int d;
    d = fun(a,b);
    fun_out(a,b+c,b,a+c);
}

на инструкции, два слова, и вы можете позвонить C

   4:   e59fd00c    ldr sp, [pc, #12]   ; 18 <fun_out+0x4>
   8:   eb000003    bl  1c <more_fun>

...

  18:   20008000    andcs   r8, r0, r0

0000001c <more_fun>:
  1c:   e92d4070    push    {r4, r5, r6, lr}
  20:   e1a05002    mov r5, r2
  24:   e1a06000    mov r6, r0
  28:   e1a04001    mov r4, r1
  2c:   ebfffff7    bl  10 <fun>
  30:   e1a00006    mov r0, r6
  34:   e0853006    add r3, r5, r6
  38:   e0851004    add r1, r5, r4
  3c:   e1a02004    mov r2, r4
  40:   ebfffff3    bl  14 <fun_out>
  44:   e8bd8070    pop {r4, r5, r6, pc}
1 голос
/ 11 октября 2011

У вас есть около двух вариантов:

  1. Настройте стек и забудьте об этом.Вы все равно должны установить указатель стека в ассемблере, поскольку вы не можете сделать это в C (если компилятор не поддерживает некоторые нестандартные расширения, позволяющие прямой доступ к регистрам).
  2. Закомментируйте оригинальную функцию C,дизассемблирование, которое вы представили выше, скопируйте код дизассемблирования, замените push / pop / bx на str / ldr / b в зависимости от ситуации (вам потребуется выделить глобальную переменную для сохранения / восстановления этих энергонезависимых регистров (fp?)), исправитьдругие вещи, если это необходимо, и перекомпилируйте его в сборочный модуль. РЕДАКТИРОВАТЬ : Подумав, вместо того, чтобы приступить к разборке, переведите эту функцию в сборку с помощью ключа -S, например, gcc -c cfile.c -S -o asmfile.s.Это, вероятно, сэкономит вам некоторую работу.

Я бы предпочел иметь действительный стек немедленно.

...