【问题标题】:A simple C program without #include <stdio.h>一个没有#include <stdio.h> 的简单C 程序
【发布时间】:2009-09-27 09:41:34
【问题描述】:

如何在不包含stdio.h的情况下直接调用“printf”?

我在这里找到了一个有趣的教程:
http://www.halcode.com/archives/2008/05/11/hello-world-c-and-gnu-as/

所以,这是我的尝试:

int main(){
 char ss[] = "hello";

 asm (
  "pushl %ebp ;"
  "movl %esp, %ebp ;"
  "subl $4, %esp ;"
  "movl $ss, (%esp) ;"
  "call _printf ;"
  "movl  $0, %eax ;"
  "leave ;"
  "ret ;"
 );

 return 0;
}

我使用的是 MinGW 4.4,下面是我的编译方式:

gcc -c hello.c -o hello.o
ld你好.o -o hello.exe C:/mingw/lib/crt2.o C:/mingw/lib/gcc/mingw32/4.4.0/crtbegin.o C:/mingw/lib/gcc/mingw32/4.4.0/crtend.o -LC:/mingw/lib/gcc/mingw32/4.4.0 -LC:/mingw/lib -lmingw32 -lgcc -lmsvcrt -lkernel32

不幸的是,它失败了:

hello.o:hello.c:(.text+0x26): 对 `ss' 的未定义引用

如何解决这个问题?

【问题讨论】:

  • 为什么需要?
  • @Ahmed - 禁止学习吗?获取知识是否受到反对?
  • 好吧,只是纯粹的好奇,我知道实际上这并不重要
  • 您不能只将汇编程序的输出粘贴到 C 程序中。例如你的'ret'只是一个回报声明。 asm 块中的前 2-3 行,设置堆栈,你不应该在 c 程序中这样做,因为 CRT 已经为每个函数插入了这样的代码。

标签: c assembly printf mingw inline-assembly


【解决方案1】:

您可以将printf 的声明复制到您的程序中。在 C 中,包含其他文件只是将其文本复制粘贴到您的程序中。因此,您可以自己进行复制粘贴来完成这项工作。

extern int printf (const char* format, ...);

int main()
{
  printf("Hello, world!\n");
  return 0;
}

链接器肯定会在库中找到正确的定义,您的程序默认链接到该库。

【讨论】:

  • 虽然这适用于回答 OP 的问题,但它巧妙地错过了 OP 的意图,这更像是如何与 GCC 一起使用内联汇编,而不是真正使用不包含 a 的函数标题。
  • @Chris Lutz:嘿,不要把我描绘成骗子! :-) 我以我理解的方式回答。无论如何,我的答案在接受后做出了很好的回答。 :-)
  • @anta40,这就是当您坚信某些语言功能(如#include 会变魔术)时所得到的结果。
【解决方案2】:
int main(void)
{
    char ss[] = "hello";

    __asm(
        "pushl %[ss]\n"    // push args to stack
        "call _puts\n"
        "addl $4, %%esp\n" // remove args from stack
        :: [ss] "r" (ss)   // no output args, no clobbered registers
    );

    /*  C equivalent:
        extern int puts(const char *);
        puts(ss);
    */
}

【讨论】:

  • @theonlygusti __asm() 允许您调用内联汇编代码。在 OS 编程中最常见(我想真的是看到任何汇编代码最常见的地方)。这是一篇不错的文章:wiki.osdev.org/Inline_Assembly
  • @rady 哪种语言?你的电脑?还是它使用了其他东西?
【解决方案3】:
int main() {

    char ss[] = "hello";
    char *p = ss;

    asm (
        "movl %0, (%%esp);"
        "call _printf;" : "=r" (p)
    );

    return 0;
}

【讨论】:

  • 这称为内联汇编。更多信息:ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
  • 那是危险的在线组装。 %esp 指向堆栈的顶部元素而不是下一个空闲元素。你可能已经像这样破坏了堆栈顶部的任何东西。你应该推 arg 然后弹出它。
  • 哇!你是对的。 Ofcource 然后我们必须向 OP 调用约定解释。 :*>
  • 这也有效。谢谢你。是的,我仍然需要学习那些调用约定,因为我是一个 asm 菜鸟。顺便说一句,什么时候将 ss 更改为“hello world”,输出是“。为什么?
  • 看看 Christoph 的例子 - 他还从堆栈中删除了 args
【解决方案4】:

很简单 然后使用 printf 语句编写一个 c 程序 以 .c 扩展名保存程序 并运行程序 它会工作.... 甚至它也可以包含像 clrscr()、getch() 这样的函数,它们是 conio.h 的一部分

【讨论】:

    猜你喜欢
    • 2012-11-29
    • 1970-01-01
    • 2013-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-27
    • 1970-01-01
    • 2012-11-20
    相关资源
    最近更新 更多