gpt4 book ai didi

c - AVR C 编译器行为。内存管理

转载 作者:太空狗 更新时间:2023-10-29 15:41:34 27 4
gpt4 key购买 nike

AVR C 编译器是否让程序记住函数开始将其数据(变量、数组)存储在索引寄存器之一的数据堆栈中的 SRAM 中的地址,以便通过公式获取局部变量的绝对地址:

absoluteAdr = functionDataStartAdr + localShiftOfVariable.

当由它的长度声明的变量或堆栈指针在所有变量长度的函数结束/开始增加时,它们是否增加数据堆栈点。

最佳答案

让我们看一下 avr-gcc,它可以免费获得,包括 its ABI :

Do AVR C compilers make program memorize the address in SRAM where function started to store its data (variables, arrays) in data stack in one of index registers in order to get absolute address of local variable by formula:

是,不是,这取决于:

静态存储

对于静态存储中的变量,即由定义的变量

unsigned char func (void)
{
static unsigned char var;
return ++var;
}

编译器生成一个像 var.123 这样大小合适的符号(本例中为 1 个字节)。然后链接器/定位器将分配地址。

func:
lds r24,var.1505
subi r24,lo8(-(1))
sts var.1505,r24
ret
.local var.1505
.comm var.1505,1,1

自动

如果可能,自动变量保存在寄存器中,否则编译器会在函数的框架中分配空间。甚至可能是变量被优化掉了,在这种情况下它们在程序中的任何地方都不存在:

int add (void)
{
int a = 1;
int b = 2;
return a + b;
}

add:
ldi r24,lo8(3)
ldi r25,0
ret

有 3 种类型的实体存储在函数的框架中,所有这些实体都可能存在或不存在,具体取决于程序:

  • 由函数序言保存(推送)并由尾声恢复(POP)的被调用方保存的寄存器。当局部变量被分配给被调用者保存的寄存器时,这是需要的。

  • 不能分配给寄存器的局部变量空间。当变量太大而无法保存在寄存器中,自动变量太多,或者变量的地址被获取(并且无法优化获取地址)时,就会发生这种情况。这是因为您不能获取寄存器1 的地址。

    void use_address (int*);

    void func (void)
    {
    int a;
    use_address (&a);
    }

    这些变量的空间在序言中分配并在尾声中释放。收缩包装未实现:

    func:
    push r28
    push r29
    rcall .
    in r28,__SP_L__
    in r29,__SP_H__
    /* prologue: function */
    /* frame size = 2 */
    /* stack size = 4 */
    movw r24,r28
    adiw r24,1
    rcall use_address
    pop __tmp_reg__
    pop __tmp_reg__
    pop r29
    pop r28
    ret

    在这个例子中,a 占用 2 个字节,由 rcall 分配。(它是为具有 16 位程序计数器的设备编译的)。然后编译器用堆栈指针的值初始化帧指针Y (R29:R28)。这是必需的,因为在 AVR 上,您不能通过 SP 访问内存;唯一涉及 SP 的内存操作是 PUSHPOP。然后,Y+1 变量的地址被传递到 R24 中。函数调用后,结语释放帧并恢复 R28 和 R29。

  • 必须在堆栈上传递的参数:

    void xfunc (int, ...);

    void call_xfunc (void)
    {
    xfunc (42);
    }

    这些参数被压入,被调用者从堆栈中取出它们。这些参数在调用期间被压入/弹出,但也可以通过 -maccumulate-args 进行累积。

    call_func:
    push __zero_reg__
    ldi r24,lo8(42)
    push r24
    rcall xfunc
    pop __tmp_reg__
    pop __tmp_reg__
    ret

    在这个例子中,参数必须在堆栈上传递,因为 ABI 规定可变参数函数的所有参数都必须在堆栈上传递,包括命名的参数。

有关框架布局和参数传递的精确描述,请参阅[框架布局和参数传递] ( https://gcc.gnu.org/wiki/avr-gcc#Frame_Layout )。

1 有些 AVR 实际上允许这样做,但您永远(就像从不)想要传递通用寄存器的地址!

关于c - AVR C 编译器行为。内存管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48570281/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com