添加函数会破坏嵌入的 C 代码(无 IDE)

问题描述 投票:0回答:1

我一直在尝试进入嵌入式 C 编程……非常裸机,只有工具链,而不是 IDE。为此,我也一直在编写自己的链接器脚本。问题是,当我的 C 代码中除了

main
之外还有任何其他函数时,
PC
SP
(程序计数器和堆栈指针寄存器)就会混乱。

我将提供代码:

链接器:

ENTRY(start)

MEMORY {
  FLASH (rw)  : ORIGIN = 0x0000000000000000, LENGTH = 0x000000000000BFFF
  RAM (rwx)   : ORIGIN = 0x0000000040000000, LENGTH = 0x000000001FFFFFFF
}

_estack = ORIGIN(RAM) + LENGTH(RAM);

SECTIONS {
  .text : {
    . = ALIGN(4);
    *(.text)
  } > FLASH

  .data : {
    . = ALIGN(4);
    _sdata = .;
    *(.data)
    *(.data*)
    . = ALIGN(4);
    _edata = .;
  } > RAM AT> FLASH

  .bss : {
    _sbss = .;
    *(.bss)
    *(.bss*)
    . = ALIGN(4);
    _ebss = .;
  } > RAM
}

ASM 文件(稍后我会添加更多内容):

.syntax unified
.cpu cortex-a8

.global start

.word _estack

.word _sbss
.word _ebss

.word _sdata
.word _edata

.section .text
start:
  ldr sp, =_estack

  b main

编译标志还有:

CFLAGS := -c \
    -g
    -march=armv7-a \
    -nostdlib

QEMU_FLAGS := -m $(MEMORY) \
    -S \
    -machine cubieboard \
    -cpu cortex-a8  \
    -gdb tcp::$(PORT)

问题演示:

C代码:

int main(void) {

    volatile int a = 0, b = 1;
    for(int i = 2; i < 4; i++) {
        int k = a + b;
        a = b;
        b = k;
    }

    return 0;
}

GDB(将架构设置为“arm”)输出:

start () at start.s:16
16        ldr sp, =_estack
(gdb) load
Loading section .text, size 0x94 lma 0x0
Start address 0x00000088, load size 148
Transfer rate: 1184 bits in <1 sec, 148 bytes/write.
(gdb) info reg
...
sp             0x0                 0x0 <main>
lr             0x0                 0
pc             0x88                0x88 <start>
cpsr           0x400001d3          1073742291
fpscr          0x0                 0
fpsid          0x410330c0          1090728128
...
Quit
(gdb) step
start () at start.s:18
18        b main
(gdb) step
main () at main.c:1
1       int main(void) {
(gdb) step
3               volatile int a = 0, b = 1;
(gdb) info reg
...
r11            0x5ffffffb          1610612731
r12            0x0                 0
sp             0x5fffffe7          0x5fffffe7
lr             0x0                 0
pc             0xc                 0xc <main+12>
cpsr           0x400001d3          1073742291
fpscr          0x0                 0
fpsid          0x410330c0          1090728128
...

即。一切都好。

当我有功能时:

C代码:

void my_func(void) {
    int volatile c = 1000;
}

int main(void) {

    volatile int a = 0, b = 1;
    for(int i = 2; i < 4; i++) {
        int k = a + b;
        a = b;
        b = k;
    }

    my_func();

    return 0;
}

GDB 输出:

start () at start.s:16
16        ldr sp, =_estack
(gdb) load
Loading section .text, size 0xbc lma 0x0
Start address 0x000000b0, load size 188
Transfer rate: 1504 bits in <1 sec, 188 bytes/write.
(gdb) step
start () at start.s:18
18        b main
(gdb) step
main () at main.c:5
5       int main(void) {
(gdb) step
my_func () at main.c:3
3       }
(gdb) print a
No symbol "a" in current context.
(gdb) info regs
Undefined info command: "regs".  Try "help info".
(gdb) info reg
...
sp             0x0                 0x0 <my_func>
lr             0x2c                44
pc             0x14                0x14 <my_func+20>
cpsr           0x400001d7          1073742295
...
(gdb) disas my_func
Dump of assembler code for function my_func:
   0x00000000 <+0>:     push    {r11}           @ (str r11, [sp, #-4]!)
   0x00000004 <+4>:     add     r11, sp, #0
   0x00000008 <+8>:     sub     sp, sp, #12
   0x0000000c <+12>:    mov     r3, #1000       @ 0x3e8
   0x00000010 <+16>:    str     r3, [r11, #-8]
=> 0x00000014 <+20>:    nop                     @ (mov r0, r0)
   0x00000018 <+24>:    add     sp, r11, #0
   0x0000001c <+28>:    pop     {r11}           @ (ldr r11, [sp], #4)
   0x00000020 <+32>:    bx      lr
End of assembler dump.
(gdb) disas main
Dump of assembler code for function main:
   0x00000024 <+0>:     push    {r11, lr}
   0x00000028 <+4>:     add     r11, sp, #4
   0x0000002c <+8>:     sub     sp, sp, #16
   0x00000030 <+12>:    mov     r3, #0
   0x00000034 <+16>:    str     r3, [r11, #-16]
   0x00000038 <+20>:    mov     r3, #1
   0x0000003c <+24>:    str     r3, [r11, #-20] @ 0xffffffec
   0x00000040 <+28>:    mov     r3, #2
   0x00000044 <+32>:    str     r3, [r11, #-8]
   0x00000048 <+36>:    b       0x78 <main+84>
   0x0000004c <+40>:    ldr     r2, [r11, #-16]
   0x00000050 <+44>:    ldr     r3, [r11, #-20] @ 0xffffffec
   0x00000054 <+48>:    add     r3, r2, r3
   0x00000058 <+52>:    str     r3, [r11, #-12]
   0x0000005c <+56>:    ldr     r3, [r11, #-20] @ 0xffffffec
   0x00000060 <+60>:    str     r3, [r11, #-16]
   0x00000064 <+64>:    ldr     r3, [r11, #-12]
   0x00000068 <+68>:    str     r3, [r11, #-20] @ 0xffffffec
   0x0000006c <+72>:    ldr     r3, [r11, #-8]
   0x00000070 <+76>:    add     r3, r3, #1
   0x00000074 <+80>:    str     r3, [r11, #-8]
   0x00000078 <+84>:    ldr     r3, [r11, #-8]
   0x0000007c <+88>:    cmp     r3, #3
   0x00000080 <+92>:    ble     0x4c <main+40>
   0x00000084 <+96>:    bl      0x0 <my_func>
   0x00000088 <+100>:   mov     r3, #0
   0x0000008c <+104>:   mov     r0, r3
   0x00000090 <+108>:   sub     sp, r11, #4
   0x00000094 <+112>:   pop     {r11, lr}
   0x00000098 <+116>:   bx      lr

(gdb) print &c
$1 = (volatile int *) 0xfffffff8

0xfffffff8 超出了链接器 skript 上写入的 RAM。

有人可以解释一下出了什么问题以及如何防止它吗?

c arm embedded qemu
1个回答
0
投票

第一个案例看起来也很奇怪。

在第一种情况下,编译器在堆栈上为变量 a、b、i、k 保留 16 个字节:

   0x00000024 <+0>:     push    {r11, lr}
   0x00000028 <+4>:     add     r11, sp, #4
   0x0000002c <+8>:     sub     sp, sp, #16

也就是说SP值应该是

0x5fffffef
但是却是
0x5fffffe7

my_func
中,编译器在堆栈上为变量 c:

保留 12 个字节
   0x00000004 <+4>:     add     r11, sp, #0
   0x00000008 <+8>:     sub     sp, sp, #12
   0x0000000c <+12>:    mov     r3, #1000       @ 0x3e8

我不明白为什么 c 需要 12 个字节,也不明白它如何以 0 结尾。 删除

volatile
限定符后会发生什么?

GDB 对流程图有何评价

i proc m

© www.soinside.com 2019 - 2024. All rights reserved.