Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Aug 2001 11:36:45 -0700 (PDT)
From:      John Baldwin <jhb@FreeBSD.org>
To:        "David O'Brien" <obrien@FreeBSD.org>
Cc:        freebsd-hackers@FreeBSD.org, Steve Roome <stephen_roome@yahoo.com>
Subject:   Re: function calls/rets in assembly
Message-ID:  <XFMail.010824113645.jhb@FreeBSD.org>
In-Reply-To: <20010824110805.C88259@dragon.nuxi.com>

next in thread | previous in thread | raw e-mail | index | archive | help

On 24-Aug-01 David O'Brien wrote:
> On Fri, Aug 24, 2001 at 01:01:39AM +0100, Steve Roome wrote:
>> How exactly should functions work in assembly, afaict, the
>> following C :
>> 
>> void printasint(int p) { printf ("print this %d\n", (int)p);}
> 
> Why not just ask the compiler??
> 
> $ cc -S -O0 printasint.c
> $ cat printasint.s
> 
> 
>       .file   "foo.c"
>       .version        "01.01"
> gcc2_compiled.:
>       .section        .rodata
> .LC0:
>       .byte    0x70,0x72,0x69,0x6e,0x74,0x20,0x74,0x68,0x69,0x73
>       .byte    0x20,0x25,0x64,0xa,0x0
> .text
>       .p2align 2,0x90
> .globl printasint
>               .type            printasint,@function
> printasint:
>       pushl %ebp
>       movl %esp,%ebp
>       subl $8,%esp
>       addl $-8,%esp
>       movl 8(%ebp),%eax
>       pushl %eax
>       pushl $.LC0
>       call printf
>       addl $16,%esp
> .L2:
>       leave
>       ret
> .Lfe1:

Because this code is broken and obfuscated? :)

We save %esp in %ebp (the only thing that keeps it from breaking) then for some
reason allocate two quadwords on the stack unnecessarily, one using an add
instruction, one using a sub.  Then we push the two dword args on the stack and
call the function.  After the call, we adjust the stack by 16, even though
we only used 8 bytes of arguments!  Thus, it seems to be reclaiming one of the
2 quadwords it allocated on the stack in addition to the arguments passed to
the function.  At this point if we did a 'pop %ebp' instead of leave, things
would break since we have a misaligned stack, but the leave restores the %esp
from %ebp, before pop'ing %ebp thus working around the bogus stack handling.

A better version would be this:

printasint:
        pushl %ebp
        movl %ebp, %esp
        pushl 8(%ebp)
        pushl $.LC0
        call printf
        addl $8,%esp
        leave
        ret

Note that with hand optimizing, you could axe the addl after the call since
leave will clean up after that anyways.  Also, you don't really need a frame
here anyways.  In that case, you could just push 8(%esp) as your first
instruction and axe the leave (but leave the addl).

-- 

John Baldwin <jhb@FreeBSD.org> -- http://www.FreeBSD.org/~jhb/
PGP Key: http://www.baldwin.cx/~john/pgpkey.asc
"Power Users Use the Power to Serve!"  -  http://www.FreeBSD.org/

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?XFMail.010824113645.jhb>