GCC generated assembly

Jeremie Le Hen jeremie at le-hen.org
Thu Dec 20 05:48:39 PST 2007


Hi list,

This mail is slightly off-topic because probably not FreeBSD-centric.

I've looked at the assembly code generated by GCC, but I am not able to
understand the point of every instruction.

I've written the following useless program:
% #include <string.h>
% 
% int
% main(int ac, char *av[])
% {
%         char buf[16];
% 
%         if (ac < 2)
%                 return 0;
%         strcpy(buf, av[1]);
%         return 1;
% }

Theorically, the main() function should be something like this:
%   push %ebp
%   mov %esp, %ebp
%   sub $16, %esp
%   cmp $1, 8(%ebp)
%   jle .byebye
%   mov 12(%ebp), %eax
%   push 4(%eax)
%   push -16(%ebp)
%   call strcpy
% byebye:
%   leave
%   ret

So the stack would look like this when calling strcpy() :

	|   av   |
	|   ac   |
	|   ret  |
	| old ebp| <- ebp
	[        ]
	[        ]
	[   buf  ]
	[        ]
        |  av[1] |
	|  &buf  | <- esp


On RELENG_6, with GCC 3.4.6, I get the following assembly:
% aristote# gcc -S -O vuln.c
% aristote# cat vuln.s
%         .file   "vuln.c"
%         .text
%         .p2align 2,,3
% .globl main
%         .type   main, @function
% main:
%         pushl   %ebp
%         movl    %esp, %ebp
%         subl    $24, %esp
%         andl    $-16, %esp
%         subl    $16, %esp
%         movl    $0, %eax
%         cmpl    $1, 8(%ebp)
%         jle     .L1
%         subl    $8, %esp
%         movl    12(%ebp), %eax
%         pushl   4(%eax)
%         leal    -24(%ebp), %eax
%         pushl   %eax
%         call    strcpy
%         movl    $1, %eax
% .L1:
%         leave
%         ret
%         .size   main, .-main
%         .ident  "GCC: (GNU) 3.4.6 [FreeBSD] 20060305"

While it works, it seems to waste much space on the stack :

	|   av   |
	|   ac   |
	|   ret  |
	| old ebp| <- ebp
	{        }
	{        }
	{24 bytes}
	{ (buf1) }
	{        }
	{        }	# There could be more space between the two
        [        ]	# buffers because of alignment on 16 bytes.
        [16 bytes]
        [ (buf2) ]
        [        ]
	{ 8 bytes}
	{ (buf3) }
        |  av[1] |
	|  &buf1 | <- esp

Is someone able to explain this please?

Interestingly, if I change the buffer size from 16 to 32 bytes, buf1 is
40 bytes wide while the two others keep the same size.

I've tried with GCC 2.95.3 from ports.  Stackwise the differences are:
	- buf2 doesn't exist
	- while buf1 is still 24 bytes long, the value passed to
	  strcpy() is buf1 + 8:
		% leal -16(%ebp),%eax
		% pushl %eax


I will follow up with RELENG_7 GCC 4.2.1 output.

Thank you.
Regards,
-- 
Jeremie Le Hen
< jeremie at le-hen dot org >< ttz at chchile dot org >


More information about the freebsd-hackers mailing list