views:

618

answers:

4

How to call "printf" directly without including stdio.h ?

I found a interesting tutorial here:
http://www.halcode.com/archives/2008/05/11/hello-world-c-and-gnu-as/

So, here's my attempt:

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;
}

I'm using MinGW 4.4, and here's how I compile it:

gcc -c hello.c -o hello.o
ld hello.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

Unfortunately, it fails:

hello.o:hello.c:(.text+0x26): undefined reference to `ss'

How to fix this?

+6  A: 

You can copy the declaration of printf into your program. In C, including other file is a mere copy-pasting its text into your program. So you can do this job by doing the copy-paste on your own.

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

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

Linker will surely find the proper definition in the libraries, against which you program is linked by default.

Pavel Shved
While this works for answering the OP's question, it neatly misses the OP's intention, which is more along the lines of how to work with inline assembly with GCC than it is really about using a function without including a header.
Chris Lutz
@PaulWow it works. I never thought such thing was possible@ChrisYes you're right. Sorry for my misleading title.
anta40
@Chris Lutz: hey, don't depict me as a fraud! :-) I answered in the way I understood. Anyway, my one makes a good second-after-accepted answer. :-)
Pavel Shved
@anta40, that's what you get when you entrench in the notion that some language features like #include do magic.
shoosh
+2  A: 
int main() {

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

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

    return 0;
}
Kapil Kapre
This is called Inline assembly. More info here: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
LiraNuna
That's dangerous in-line assembly. %esp points to the top element of the stack NOT the next free element. You may have clobbered whatever is at the top of the stack like that. You should push the arg then pop it after.
Falaina
doh ! You're right. Ofcource then we'd have to explain to OP calling conventions. :*>
Kapil Kapre
That works too. Thank you. Yeah, I still neet to learn those calling conventions, since I'm an asm noob.BTW, when is change ss into "hello world", the output is ".Why?
anta40
look at the example from Christoph - he removes also the args from the stack
elcuco
+1  A: 
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);
    */
}
Christoph
A: 

Its very ease Write one c program using printf statement then save the program with .c extension and Run the program It will work.... Even it can contain function like clrscr(), getch() which are part of conio.h

Kapil Shukla