26

I'm trying to use a function in assembly, invoked from a C project. This function is supposed to call a libc function let's say printf(), but I keep getting a segmentation fault.

In the .c file I have the declaration of the function let's say

int do_shit_in_asm() 

In the .asm file I have

.extern printf .section .data printtext: .ascii "test" .section .text .global do_shit_in_asm .type do_shit_in_asm, @function do_shit_in_asm: pushl %ebp movl %esp, %ebp push printtext call printf movl %ebp, %esp pop %ebp ret 

Any pointers comments would be appreciated.

as func.asm -o func.o gcc prog.c func.o -o prog 
4
  • 37
    "Any pointers would be appreciated": int *ptr; Commented Jan 13, 2011 at 3:55
  • @Sapph +1 but it doesn't help :)) Commented Jan 13, 2011 at 3:56
  • 12
    @Sapph: You meant void*, right? Commented Jan 13, 2011 at 4:04
  • 1
    @Lambert: It's so painfully obvious in retrospect! I'm ashamed. +1 to you sir. Commented Jan 13, 2011 at 4:42

4 Answers 4

16

Change push printtext to push $printtext.

As it is, you're loading a value from the address printtext and pushing that, rather than pushing the address. Thus, you're passing 'test' as a 32-bit number, rather than a pointer, and printf is trying to interpret that as an address and crashing.

Sign up to request clarification or add additional context in comments.

Comments

9

One of the best ways to get started with assembly language functions is to write a similar function in C, and then build it with the compiler switch that generates an assembly listing (-S on gcc). Then you can study the output of what the compiler did, and modify as needed.

This is particularly useful if you're calling functions such as printf which use a different calling convention (because of the variable number of arguments). Calling those functions may be quite different from calling non-varargs functions.

1 Comment

Very educational... but also typically very misleading. The real issue is the ABI specific details of what registers must be preserved, what they mean, and how they interact w/the C ABI. I went down this path initially and then realized that my assembly would be no better than what the compiler would generate which was exactly the opposite of what I was trying to achieve!
6

the issue was that i was using

pushl printtext 

rather that

pushl $printtext 

Thanks everybody for your help and sorry for wasting your time :P

1 Comment

You got it just before I posted. Congrats on solving your problem. :-)
2

After this:

push printtext call printf 

You want:

addl $4, %esp 

Further explanation:

Because you're using x86 Linux I assume the calling convention requires the callee to cleanup the parameters. Because you pushed a pointer before calling printf, your stack is off by 4 after that function's ret instruction happened.

Update:

Yeah, OK, I was used to Intel syntax so I was getting the order of the arguments backward in my head. Actually the lack of the addl back to esp doesn't matter, because you're restoring esp correctly near your ret. My next guess is that the string you're passing to printf is lacking a null terminator... Let me see what gas does...

Update 2:

OK, gas null terminates strings for you, so I guess my second hunch was wrong. It looks like you found the issue so the point is moot.

3 Comments

I got confused because I'm used to Intel syntax, not AT&T. You actually want addl $4, %esp Hold on, let me take another look...
@void - Maybe you can check in a hex editor. Does the string you pass to printf get null terminated?
right it's $4, %esp i found the issue, I should have pushed on the stack pushl $prittext