C 字符串在循环中没有正确迭代

标签 c arrays arm embedded beagleboneblack

我正在尝试通过 Beaglebone Black 的 UART0 打印字符串。引导加载程序初始化 UART0,我只需要写入字符。我做了一个简单的函数

void uart_put(unsigned char c)
{
    while((UART0->LSR_r & 32) == 0);
    UART0->THR = c;     
}

从启动代码中调用了以下函数,我只是在该函数中打印字符。

#define SIZE_OF_ARRAY 7 
int c_entry(void)
{
unsigned char s_name[SIZE_OF_ARRAY] = "Hello";
unsigned char a_name[SIZE_OF_ARRAY] = {'H','e','l','l','o','\0'};
unsigned int a_int[SIZE_OF_ARRAY] = {9,8,7,6,5,4};
int i = 0;
    for(i = 0; i<6; i++)
    {
      uart_put('0'+i);      /*print value of i*/
      uart_put(9);          /*print a tab*/
      uart_put(s_name[i]);  /*print char from string*/
      uart_put(9);          /*print a tab*/
      uart_put(a_name[i]);  /*print char from array*/
      uart_put(9);          /*print a tab*/
      uart_put('0'+a_int[i]);   /*print int from array*/
      uart_put('\n');
      uart_put('\r');
    }   
    while(1);
    return 0;
}

该函数作为字符数组工作正常,整数打印正确,但字符串未按应有的方式打印。 enter image description here

最佳答案

在链接描述文件中,更改:

. = 0x402F0400;

到:

. = 0x80000000;

根据 memory map for the AM335X ARM processor , 0x402F0400 是核心 SRAM 而 0x8000000 是 DDR2 内存。根据 TFTP 引导输出的屏幕截图,您在 0x80000000 加载您的应用程序,但您的链接描述文件配置为引用 0x402F04000 的内存。

反汇编使用原始链接脚本生成的原始二进制文件 download.bin 产生:

% arm-none-eabi-objdump -D -b binary -marm download.bin
download.bin:     file format binary

Disassembly of section .data:

00000000 <.data>:
    0:   e51fd000        ldr     sp, [pc, #-0]   ; 0x8
    4:   eb00000e        bl      0x44
    8:   402f1638        eormi   r1, pc, r8, lsr r6      ; <UNPREDICTABLE>
    c:   e52db004        push    {fp}            ; (str fp, [sp, #-4]!)
    [removed several lines of text]
    4c:   e24dd030        sub     sp, sp, #48     ; 0x30
    50:   e300262c        movw    r2, #1580       ; 0x62c
    54:   e344202f        movt    r2, #16431      ; 0x402f
    [remainder of dump removed]

字符串从内存中复制到局部变量中。请注意,字符串副本的地址是 0x402f062c(movwmovt 命令将地址加载到寄存器中)。快速扫描省略的代码不会显示任何其他访问内存的尝试。

我无法访问 Beaglebone Black,因此无法对此进行测试。它确实解释了观察到的行为。由于程序正在从未初始化的 SRAM 中复制字符串,因此无法保证会显示什么。由于程序中没有其他访问内存的尝试,因此这是唯一的问题。

更改链接描述文件并重新构建会导致 download.bin 略有不同。原始链接器脚本生成的反汇编 download.bin 与我建议的更改之间的差异是:

10c10
<    8: 402f1638        eormi   r1, pc, r8, lsr r6      ; <UNPREDICTABLE>
---
>    8: 80001238        andhi   r1, r0, r8, lsr r2
28,29c28,29
<   50: e300262c        movw    r2, #1580       ; 0x62c
<   54: e344202f        movt    r2, #16431      ; 0x402f
---
>   50: e300222c        movw    r2, #556        ; 0x22c
>   54: e3482000        movt    r2, #32768      ; 0x8000

您可以清楚地看到复制字符串的新地址引用。不幸的是,我不确定其他更改是什么以及此更改是否会导致任何问题。

为了验证字符串位于 0x8000022c,我们可以使用 xxd 转储 download.bin。输出是:

% xxd download.bin
0000000: 00d0 1fe5 0e00 00eb 3816 2f40 04b0 2de5  ........8./@..-.
0000010: 00b0 8de2 14d0 4de2 0030 a0e1 0d30 4be5  ......M..0...0K.
[... omitted lots of lines ...]
0000220: 0500 53e3 cdff ffda feff ffea 4865 6c6c  ..S.........Hell
0000230: 6f00 0000                                o...

字符串 Hello0x22c 可见。当加载到 0x80000000 时,复制字符串的地址看起来是正确的。

关于C 字符串在循环中没有正确迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40681042/

相关文章:

c - 重叠内存最佳实践

java - jni jiniArray 作为输出参数不会改变参数值

javascript - 无法从 JSON 数组和对象获取值

c# - 摆脱 C# 数组中的 null/空字符串值

android - 在 Android 上将 .so 代码从 ARM 转换为 x86

arm - 为什么ARM有16个寄存器?

android-emulator - Qemu 中的 ARM NEON 支持

c - 如何多次附加到字符串?

C scanf 字符数组

c - 2 个静态进程的问题,它使用打开的 mpi 创建 2 个动态进程