是否可以在Linux上没有链接libc的情况下将C转换为asm?

测试平台在Linux 32位上。 (但也欢迎Windows 32位上的某些解决方案)

这是交响代码段:

int a = 0; printf("%d\n", a); 

如果我使用gcc生成汇编代码

 gcc -S test.c 

然后我会得到:

  movl $0, 28(%esp) movl 28(%esp), %eax movl %eax, 4(%esp) movl $.LC0, (%esp) call printf leave ret 

而这个汇编代码需要链接到libc才能工作(因为调用printf)

我的问题是:

是否可以将C转换为asm,只使用显式使用系统调用 ,而不使用libc?

像这样:

  pop ecx add ecx,host_msg-host_reloc mov eax,4 mov ebx,1 mov edx,host_msg_len int 80h mov eax,1 xor ebx,ebx int 80h 

直接调用int 80h软件中断。

可能吗? 如果是这样,这个问题上有什么工具吗?

谢谢!

不是来自那个源代码。 对printf()调用不能被编译器转换为对write系统调用的调用 – printf()库函数包含大量逻辑,这些逻辑在系统调用中不存在(例如处理格式字符串和转换整数和浮点数到字符串)。

可以直接生成系统调用,但只能使用内联汇编。 例如,要生成对_exit(0)的调用_exit(0)exit()不完全相同!),您可以编写:

 #include  ... int retval; asm("int $0x80" : "=a" (retval) : "a" (__NR_exit), "b" (0)); 

有关GCC内联汇编的更多信息,特别是我在这里用于将变量映射到寄存器的约束,请阅读GCC内联汇编HOWTO 。 它相当陈旧,但仍然完全相关。

请注意, 建议不要这样做。 系统调用的确切调用约定(例如,哪些寄存器用于调用号和参数,如何返回错误 )在不同的体系结构,操作系统甚至32位和64位x86之间是不同的。 以这种方式编写代码将使维护变得非常困难。

您当然可以将C代码编译为汇编而无需链接到libc,但您不能使用C库函数。 Libc的全部目的是提供从C库函数到Linux系统调用(或Windows,或者您正在使用的任何系统)的接口。 因此,如果您不想使用libc,则必须将自己的包装器写入系统调用。

如果你编译一些不使用C库中的任何函数的C代码(例如,不使用printfmalloc等等……)在GCC编译器的独立模式下(即使用-creestanding flag to gcc ) ,您需要调用一些汇编程序函数(来自其他一些对象或库)或使用asm指令(如果不进行系统调用,您将无法进行任何类型的输入输出)。

另请阅读Assembly HowTo , x86调用约定和与内核相关的ABI (可能是x86-64 ABI ),并且很好地理解什么是系统调用 ,从syscalls(2)开始 ,什么是VDSO (int 80不是最近制作系统调用的最佳方法, SYSENTER通常更好)。 研究一些libc的源代码,特别是MUSL libc (源代码非常易读)。

在Windows上(这不是免费软件,我不知道),问题可能会困难得多:我不确定系统调用级别是否完全记录完整。

libffi使您可以从C调用任意函数。您还可以从dlsym(3)转换函数指针。 你可以考虑JIT技术(例如libjit ,GNU lightning , asmjit等……)。