我有以下问题 - 我已经完成了烘焙 pi 类(class),没有任何问题,然后我决定将这个纯 asm 与一些 C 链接。我已经做到了,就我决定使用而言,一切都很好函数 sprintf 将 int 转换为 char*。现在,当我尝试编译时,我正在享受以下错误
ctesty.c:(.text+0x20): 未定义对“sprintf”的引用
make: *** [build/output.elf] 错误 1
当然,我已经包含了 stdio.h,我也试图将这个库直接包含在 makefile 中,但没有成功。
最佳答案
您想与 libc.so
链接。尝试在您的 makefile 的链接步骤中添加 -lc
。
在更好地理解问题后更新
Baking Pi示例构建一个 kernel.img
来代替通常的 Linux 内核运行。这意味着 C 标准库不可用。您需要提供自己的 sprintf()
实现,例如:
- 改编此 BSD 许可 ee_printf.c
- 移除
uart_send_char()
- 通过使
buf
成为函数参数,将ee_printf()
适配到sprintf()
为什么用户空间 libc 在任何内核中都没有源代码修改就无法工作
概念上:
- C 标准库包含处理动态内存分配(
malloc
、free
)、文件系统(fopen
、)的工具fclose
和所有 stdio)、环境变量(getenv
)、错误处理工具,如setjmp
longjmp
等等。 - 考虑:您将如何在操作系统下运行的程序中实现
malloc
?- 回答:您需要一些接口(interface)来向操作系统请求额外的内存,例如Linux 下的
brk
、sbrk
和mmap
。 - 在操作系统内核中,
brk
、mmap
等不是分配内存的正确接口(interface)。 - 因此,尽管大多数非玩具内核提供类似
malloc
的设施,但它们将无法使用未修改的用户空间malloc
实现。
- 回答:您需要一些接口(interface)来向操作系统请求额外的内存,例如Linux 下的
- 在操作系统内核中,
fopen
、getenv
等函数并不是那么有用。大多数内核编写者选择不包含它们。 - 因此大多数内核不包含完整的 C 标准库实现,而只包含内核编写者认为有用的函数。
在更机械的意义上:
- Baking Pi Makefile使用命令生成内核 ELF 镜像
$(ARMGNU)-ld --no-undefined $(OBJECTS) -Map $(MAP) -o $(BUILD)output.elf -T $(LINKER)
。这不会将build/output.elf
与任何 libc 实现链接起来,因此链接器将无法找到名为sprintf
的符号。 - 当您使用
gcc T.c -o T
构建程序时,gcc 会隐式链接到 libc 中,除非传递了诸如-nostdlib
之类的选项。
但概念上重要的几点是:
- 在内核中有用的 C 标准库部分需要不同的实现
- libc 的许多其他部分在内核中用处不大
有针对裸机环境的 C 标准库实现。参见例如 newlib .
关于c - 用 C 和基本库烘焙 PI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24367079/