【问题标题】:Assembly incbin file and use in C file + GCC 5.4.0汇编 incbin 文件并在 C 文件 + GCC 5.4.0 中使用
【发布时间】:2018-12-14 04:32:42
【问题描述】:

我有一个汇编文件。我将使用这个文件来包含一个二进制文件,如下所示:

.section .bindata

.global imrdls_start
.type imrdls_start, @object

.global imr_SW_DL_start
.type imr_SW_DL_start, @object

.section .bindata
.balign 64
imrdls_start:
imr_SW_DL_start:
    .incbin "file.bin"
    .balign 1
imr_SW_DL_end:
    .byte 0

然后在 C 文件中,我将调用该变量并使用该二进制文件的内容。

int main(void) {
    extern uint8_t imrdls_start;
    uint8_t *ptrToExpectedDL = &imrdls_start;

    for(int i = 0; i < 135; i++)
    {
        printf("0x%02x ", ptrToExpectedDL[i]);
        if((((i + 1) % 15) == 0)) printf("\n");
    }

    return EXIT_SUCCESS;
}

问题是,编译执行后,“file.bin”打印出来的内容不正确。

预期的结果是:00 1d 81 ff 00 fe 00 ff 00 1e 82 00 00 20 82 ...

垃圾输出打印为:7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 ...

下面是我的编译器和链接选项:

qcc -Vgcc_ntoaarch64le -c -Wp,-MMD,build/aarch64le-debug/src/imrdls.d,-MT,build/aarch64le-debug/src/imrdls.o -o build/aarch64le-debug/src/imrdls.o  -Wall -fmessage-length=0 -g -O0 -fno-builtin  src/imrdls.s
qcc -Vgcc_ntoaarch64le -c -Wp,-MMD,build/aarch64le-debug/src/Test.d,-MT,build/aarch64le-debug/src/Test.o -o build/aarch64le-debug/src/Test.o  -Wall -fmessage-length=0 -g -O0 -fno-builtin  src/Test.c
qcc -Vgcc_ntoaarch64le -o build/aarch64le-debug/Test   build/aarch64le-debug/src/Test.o build/aarch64le-debug/src/imrdls.o  

任何 cmets 都会非常有帮助。谢谢。

【问题讨论】:

  • 您声明了extern uint8_t imrdls_start; inside main,而不是全局范围。你试过在外面声明吗?似乎并没有改变 asm 符号名称(godbolt.org/z/aiRMgh),但有点奇怪。此外,您可以将其声明为 extern uint8_t imrdls_start[],以便编译器知道它是一个数组对象。
  • 你的程序打印什么?它应该打印什么?这不是minimal reproducible example
  • 是的@PeterCordes,我使用了十六进制转储。构建时没有错误或警告。我确定 file.bin 因为如果我将它移到其他地方,它会通知错误没有文件。
  • @PeterCordes 真的很奇怪,我尝试使用 .byte 0x00, 0x1d, 0x81,.. 如你所说。输出值仍然是 7f 45 4c 46 02 01 01...看来我必须对 .bindata 部分做一些事情,比如把它放到 RAM 中,你有什么想法
  • @PeterCordes 我只是研究了.section,你说得对,我们必须记住。我刚想出使用 .rodata 然后我看到你的评论:D。我真的很感谢你的帮助。非常感谢

标签: c gcc assembly


【解决方案1】:

如果您查看垃圾输出“7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00”,您会发现它与 elf 标头相同。 link

当使用 .section 指令创建新节时,必须提供该节的属性和类型。用这个替换你的程序集文件中的第一行应该可以:

.section .bindata , "a", @progbits

a 将该部分标记为可分配的。 ("aw" 也可以使其可写,但常量不需要它。您可以使用 "aw" 等效于 .data,而不是 .rodata。)

如果未指定标志,则默认标志取决于节名称。如果节名无法识别,则默认情况下该节没有任何标志:它不会被分配到内存中,也不会被写入,也不会被执行。该部分将包含数据。 Reference

【讨论】:

  • OP 确认他们文件的 hexdump 是他们所期望的。但是很好地发现它是一个 ELF 标头-我猜这些字节来自 OP 正在创建的链接可执行文件的开头。 (显然,自定义部分中的符号最终会解析到映射可执行文件的页面的开头。)
  • 遇到了问题,当使用 .section 指令创建新部分时,必须提供该部分的属性和类型。将汇编文件中的第一行替换为 ".section .bindata , "aw", @progbits" 即可。说明:据我了解,您的整个 asm 文件代码都使用 .bindata 部分,链接器将整个 .o 文件放在 bindata 部分中,并且由于 imrdls_start 指向 bindata 部分的开头,因此您的 asm 文件的 .o 文件得到打印。这就是我们在垃圾箱中看到 elf 文件头的原因。
  • 听起来不错,您应该edit您的答案,用您上次评论中的正确信息替换错误的部分。尤其是权限 + @progbits 部分是我认为将数据映射到内存的原因。
  • 谢谢@PeterCordes
  • 没有迹象表明 OP 希望该部分可写。他们只是从中阅读。如果可能,最好将其设为只读,以便映射共享。
【解决方案2】:

您的数据位于具有非标准名称.bindata 的部分中。我不知道链接器将它放在哪里,但显然它没有映射到运行程序时从文件加载(或内存映射)的可执行段。

除非您确实需要控制包含的数据相对于编译器生成的只读数据的布局,否则只需将您的数据放入.section .rodata

(我很惊讶链接器没有抱怨,并且您在运行时没有收到段错误。我希望至少有一个段错误,而不是默默地获取虚假数据。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-19
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多