Hello Assembly Expert and Professional,

I am trying to understand the whole calling convention process.

Here is my test4.c source code:


#include <stdio.h>
#include <stdlib.h>

/*Global Variable*/
int a = 1;

void stack2(int d)
{
   /*Local Stack 2 Variable*/
   int f = d;
   printf("Parameter d: %i\nLocal variable f: %i\n", d, f);

   printf("Stack 2\n");

   if(f == 1)
   {
       printf("Calling Stack 3\n");
   }
   else
   {
       printf("Exiting Stack2()\n");

       printf("Parameter d: %i\nLocal variable f: %i\n", d, f);
   }

   printf("Exiting Stack2()\n");
   printf("Parameter d: %i\nLocal variable f: %i\n", d, f);

}

void stack1(int c)
{
   /*Local Stack 1 Variable*/
   int e = c;
   printf("Parameter c: %i\nLocal variable e: %i\n", c, e);
   
   printf("Stack 1\n");

   if(e == 1)
   {
       printf("Calling Stack 2\n");

       stack2(e);
   }
   else
   {
       printf("Exiting Stack1()\n");
       printf("Parameter c: %i\nLocal variable e: %i\n", c, e);
   }

   printf("Exiting Stack1()\n");
   printf("Parameter c: %i\nLocal variable e: %i\n", c, e);

}

int main(int argc, char** argv)
{
   /*Local Main Variable*/
   int b = a;
   printf("Local variable b: %i\n", b);

   
   printf("Main\n");

   /*Calling Stack 1*/
   stack1(b);

   printf("Exiting Main()\n");
   printf("Local variable b: %i\n", b);

   return (EXIT_SUCCESS);
}


I convert it into assembly

gcc -S -masm=intel -o test4.s test4.c

test4.s:


file "test4.c"
.intel_syntax noprefix
.globl _a
.data
.align 4
_a:
.long 1
.section .rdata,"dr"
.align 4
LC0:
.ascii "Parameter d: %i\12Local variable f: %i\12\0"
LC1:
.ascii "Stack 2\0"
LC2:
.ascii "Calling Stack 3\0"
LC3:
.ascii "Exiting Stack2()\0"
.text
.globl _stack2
.def _stack2; .scl 2; .type 32; .endef
_stack2:
push ebp
mov ebp, esp
sub esp, 40
mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC0
call _printf
mov DWORD PTR , OFFSET FLAT:LC1
call _puts
cmp DWORD PTR , 1
jne L2
mov DWORD PTR , OFFSET FLAT:LC2
call _puts
jmp L3
L2:
mov DWORD PTR , OFFSET FLAT:LC3
call _puts
mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC0
call _printf
L3:
mov DWORD PTR , OFFSET FLAT:LC3
call _puts
mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC0
call _printf
leave
ret
.section .rdata,"dr"
.align 4
LC4:
.ascii "Parameter c: %i\12Local variable e: %i\12\0"
LC5:
.ascii "Stack 1\0"
LC6:
.ascii "Calling Stack 2\0"
LC7:
.ascii "Exiting Stack1()\0"
.text
.globl _stack1
.def _stack1; .scl 2; .type 32; .endef
_stack1:
push ebp
mov ebp, esp
sub esp, 40
mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
mov DWORD PTR , OFFSET FLAT:LC5
call _puts
cmp DWORD PTR , 1
jne L6
mov DWORD PTR , OFFSET FLAT:LC6
call _puts
mov eax, DWORD PTR
mov DWORD PTR , eax
call _stack2
jmp L7
L6:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts
mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
L7:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts
mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
leave
ret
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC8:
.ascii "Local variable b: %i\12\0"
LC9:
.ascii "Main\0"
LC10:
.ascii "Exiting Main()\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
lea ecx,
and esp, -16
push DWORD PTR
push ebp
mov ebp, esp
push ecx
sub esp, 36
call ___main
mov eax, DWORD PTR _a
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC8
call _printf
mov DWORD PTR , OFFSET FLAT:LC9
call _puts
mov eax, DWORD PTR
mov DWORD PTR , eax
call _stack1
mov DWORD PTR , OFFSET FLAT:LC10
call _puts
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC8
call _printf
mov eax, 0
add esp, 36
pop ecx
pop ebp
lea esp,
ret
.def _puts; .scl 2; .type 32; .endef
.def _printf; .scl 2; .type 32; .endef


So I decided to modify the stack (ESP & EBP) to play around with it:


.file "test4.c"
.intel_syntax noprefix
.globl _a
.data
.align 4
_a:
.long 1
.section .rdata,"dr"
.align 4
LC0:
.ascii "Parameter d: %i\12Local variable f: %i\12\0"
LC1:
.ascii "Stack 2\0"
LC2:
.ascii "Calling Stack 3\0"
LC3:
.ascii "Exiting Stack2()\0"
.text
.globl _stack2
.def _stack2; .scl 2; .type 32; .endef
_stack2:
push ebp
mov ebp, esp
sub esp, 4

mov eax, DWORD PTR
mov DWORD PTR , eax

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC0
call _printf

mov DWORD PTR , OFFSET FLAT:LC1
call _puts

cmp DWORD PTR , 1
jne L2

mov DWORD PTR , OFFSET FLAT:LC2
call _puts

jmp L3
L2:
mov DWORD PTR , OFFSET FLAT:LC3
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC0
call _printf
L3:
mov DWORD PTR , OFFSET FLAT:LC3
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC0
call _printf

leave
ret
.section .rdata,"dr"
.align 4
LC4:
.ascii "Parameter c: %i\12Local variable e: %i\12\0"
LC5:
.ascii "Stack 1\0"
LC6:
.ascii "Calling Stack 2\0"
LC7:
.ascii "Exiting Stack1()\0"
.text
.globl _stack1
.def _stack1; .scl 2; .type 32; .endef
_stack1:
push ebp
mov ebp, esp
sub esp, 4

mov eax, DWORD PTR
mov DWORD PTR , eax

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf

ov DWORD PTR , OFFSET FLAT:LC5
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf

cmp DWORD PTR , 1
jne L6

mov DWORD PTR , OFFSET FLAT:LC6
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
call _stack2

jmp L7
L6:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
L7:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf

leave
ret
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC8:
.ascii "Local variable b: %i\12\0"
LC9:
.ascii "Main\0"
LC10:
.ascii "Exiting Main()\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
lea ecx,
and esp, -16
push DWORD PTR
push ebp
mov ebp, esp
push ecx

sub esp, 4

call ___main

mov eax, DWORD PTR _a
mov DWORD PTR , eax

mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC8
call _printf

mov DWORD PTR , OFFSET FLAT:LC9
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC8
call _printf

mov eax, DWORD PTR
mov DWORD PTR , eax
call _stack1

mov DWORD PTR , OFFSET FLAT:LC10
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC8
call _printf

mov eax, 0
add esp, 4

pop ecx
pop ebp
lea esp,
ret
.def _puts; .scl 2; .type 32; .endef
.def _printf; .scl 2; .type 32; .endef


and my error output:

gcc -o test4.exe test4.s

test4.exe:


Local variable b: 1
Main
Local variable b: 1
Parameter c: 1
Local variable e: 1
Stack 1
Parameter c: 1
Local variable e: 4202774
Exiting Stack1()
Parameter c: 1
Local variable e: 4202798
Exiting Stack1()
Parameter c: 1
Local variable e: 4202798
     3 test4 3704 _cygtls::handle_exceptions: Error while dumping state
(probably corrupted stack)
Segmentation fault (core dumped)


I noticed that there was a change on EBP after the printf() or puts() function has been called.

However, it can be fix by changing the sub esp, 8 beside sub esp, 4.... but why? Since I only have 1 variable.....

Anyone mind enlighten me?

Thanks.

Posted on 2010-03-10 23:39:58 by deathhex

I noticed that there was a change on EBP after the printf() or puts() function has been called.

However, it can be fix by changing the sub esp, 8 beside sub esp, 4.... but why? Since I only have 1 variable.....

Anyone mind enlighten me?

Thanks.


Try compiling with the optimization flag (-O): gcc -O -S -masm=intel -o test4.s test4.c
Without optimizations, the compiler will just use the most basic translation from C to assembly possible. It will not look for any opportunity to combine multiple operations into one.
Posted on 2010-03-11 02:06:33 by Scali
It isn't entirely clear to me what you've done. Changed "sub esp, 40" to "sub esp, 4"??? You're clobbering your stack when you do "mov ", etc. I think. Look closely at why gcc is subtracting 40. I believe it's leaving a "reusable argument area" used for calls to printf, etc. Rather than pushing parameters and cleaning up the stack afterwards, as we might do, gcc has been doing it this way for... a while. Without subtracting "enough" from esp, kaboom! I *think* that's what's happening...

Best,
Frank

Posted on 2010-03-11 03:45:14 by fbkotler


I noticed that there was a change on EBP after the printf() or puts() function has been called.

However, it can be fix by changing the sub esp, 8 beside sub esp, 4.... but why? Since I only have 1 variable.....

Anyone mind enlighten me?

Thanks.


Try compiling with the optimization flag (-O): gcc -O -S -masm=intel -o test4.s test4.c
Without optimizations, the compiler will just use the most basic translation from C to assembly possible. It will not look for any opportunity to combine multiple operations into one.


gcc -O -S -masm=intel -o test4.s test4.c


.file "test4.c"
.intel_syntax noprefix
.section .rdata,"dr"
.align 4
LC0:
.ascii "Parameter d: %i\12Local variable f: %i\12\0"
LC1:
.ascii "Stack 2\0"
LC2:
.ascii "Calling Stack 3\0"
LC3:
.ascii "Exiting Stack2()\0"
.text
.globl _stack2
.def _stack2; .scl 2; .type 32; .endef
_stack2:
push ebp
mov ebp, esp
push ebx
sub esp, 20
mov ebx, DWORD PTR
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC0
call _printf
mov DWORD PTR , OFFSET FLAT:LC1
call _puts
cmp ebx, 1
jne L2
mov DWORD PTR , OFFSET FLAT:LC2
call _puts
jmp L3
L2:
mov DWORD PTR , OFFSET FLAT:LC3
call _puts
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC0
call _printf
L3:
mov DWORD PTR , OFFSET FLAT:LC3
call _puts
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC0
call _printf
add esp, 20
pop ebx
pop ebp
ret
.section .rdata,"dr"
.align 4
LC4:
.ascii "Parameter c: %i\12Local variable e: %i\12\0"
LC5:
.ascii "Stack 1\0"
LC6:
.ascii "Calling Stack 2\0"
LC7:
.ascii "Exiting Stack1()\0"
.text
.globl _stack1
.def _stack1; .scl 2; .type 32; .endef
_stack1:
push ebp
mov ebp, esp
push ebx
sub esp, 20
mov ebx, DWORD PTR
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
mov DWORD PTR , OFFSET FLAT:LC5
call _puts
cmp ebx, 1
jne L6
mov DWORD PTR , OFFSET FLAT:LC6
call _puts
mov DWORD PTR , 1
call _stack2
jmp L7
L6:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
L7:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
add esp, 20
pop ebx
pop ebp
ret
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC8:
.ascii "Local variable b: %i\12\0"
LC9:
.ascii "Main\0"
LC10:
.ascii "Exiting Main()\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
lea ecx,
and esp, -16
push DWORD PTR
push ebp
mov ebp, esp
sub esp, 24
mov DWORD PTR , ecx
mov DWORD PTR , ebx
call ___main
mov ebx, DWORD PTR _a
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC8
call _printf
mov DWORD PTR , OFFSET FLAT:LC9
call _puts
mov DWORD PTR , ebx
call _stack1
mov DWORD PTR , OFFSET FLAT:LC10
call _puts
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC8
call _printf
mov eax, 0
mov ecx, DWORD PTR
mov ebx, DWORD PTR
mov esp, ebp
pop ebp
lea esp,
ret
.globl _a
.data
.align 4
_a:
.long 1
.def _printf; .scl 2; .type 32; .endef
.def _puts; .scl 2; .type 32; .endef



I think it work because of mov instructions...




It isn't entirely clear to me what you've done. Changed "sub esp, 40" to "sub esp, 4"??? You're clobbering your stack when you do "mov ", etc. I think. Look closely at why gcc is subtracting 40. I believe it's leaving a "reusable argument area" used for calls to printf, etc. Rather than pushing parameters and cleaning up the stack afterwards, as we might do, gcc has been doing it this way for... a while. Without subtracting "enough" from esp, kaboom! I *think* that's what's happening...

Best,
Frank


Yes, I am trying to understand it that why I toying around with the turn out to be unwanted result.

Referring to http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames


void stack1(int c)
{
    /*Local Stack 1 Variable*/
    int e = c;
    printf("Parameter c: %i\nLocal variable e: %i\n", c, e);
   
    printf("Stack 1\n");

    if(e == 1)
    {
        printf("Calling Stack 2\n");

        stack2(e);
    }
    else
    {
        printf("Exiting Stack1()\n");
        printf("Parameter c: %i\nLocal variable e: %i\n", c, e);
    }

    printf("Exiting Stack1()\n");
    printf("Parameter c: %i\nLocal variable e: %i\n", c, e);

}


if the C source code converted to assembly source code, it should look like


LC4:
.ascii "Parameter c: %i\12Local variable e: %i\12\0"
LC5:
.ascii "Stack 1\0"
LC6:
.ascii "Calling Stack 2\0"
LC7:
.ascii "Exiting Stack1()\0"
.text
.globl _stack1
.def _stack1; .scl 2; .type 32; .endef
_stack1:
push ebp
mov ebp, esp
sub esp, 4

mov eax, DWORD PTR
mov DWORD PTR , eax

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf

mov DWORD PTR , OFFSET FLAT:LC5
call _puts

cmp DWORD PTR , 1
jne L6

mov DWORD PTR , OFFSET FLAT:LC6
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
call _stack2

jmp L7
L6:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
L7:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf

        add esp, 4
leave
ret
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
Posted on 2010-03-11 08:43:23 by deathhex
Sorry for grammatical mistake



I noticed that there was a change on EBP after the printf() or puts() function has been called.

However, it can be fix by changing the sub esp, 8 beside sub esp, 4.... but why? Since I only have 1 variable.....

Anyone mind enlighten me?

Thanks.


Try compiling with the optimization flag (-O): gcc -O -S -masm=intel -o test4.s test4.c
Without optimizations, the compiler will just use the most basic translation from C to assembly possible. It will not look for any opportunity to combine multiple operations into one.


gcc -O -S -masm=intel -o test4.s test4.c


.file "test4.c"
.intel_syntax noprefix
.section .rdata,"dr"
.align 4
LC0:
.ascii "Parameter d: %i\12Local variable f: %i\12\0"
LC1:
.ascii "Stack 2\0"
LC2:
.ascii "Calling Stack 3\0"
LC3:
.ascii "Exiting Stack2()\0"
.text
.globl _stack2
.def _stack2; .scl 2; .type 32; .endef
_stack2:
push ebp
mov ebp, esp
push ebx
sub esp, 20
mov ebx, DWORD PTR
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC0
call _printf
mov DWORD PTR , OFFSET FLAT:LC1
call _puts
cmp ebx, 1
jne L2
mov DWORD PTR , OFFSET FLAT:LC2
call _puts
jmp L3
L2:
mov DWORD PTR , OFFSET FLAT:LC3
call _puts
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC0
call _printf
L3:
mov DWORD PTR , OFFSET FLAT:LC3
call _puts
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC0
call _printf
add esp, 20
pop ebx
pop ebp
ret
.section .rdata,"dr"
.align 4
LC4:
.ascii "Parameter c: %i\12Local variable e: %i\12\0"
LC5:
.ascii "Stack 1\0"
LC6:
.ascii "Calling Stack 2\0"
LC7:
.ascii "Exiting Stack1()\0"
.text
.globl _stack1
.def _stack1; .scl 2; .type 32; .endef
_stack1:
push ebp
mov ebp, esp
push ebx
sub esp, 20
mov ebx, DWORD PTR
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
mov DWORD PTR , OFFSET FLAT:LC5
call _puts
cmp ebx, 1
jne L6
mov DWORD PTR , OFFSET FLAT:LC6
call _puts
mov DWORD PTR , 1
call _stack2
jmp L7
L6:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
L7:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts
mov DWORD PTR , ebx
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
add esp, 20
pop ebx
pop ebp
ret
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC8:
.ascii "Local variable b: %i\12\0"
LC9:
.ascii "Main\0"
LC10:
.ascii "Exiting Main()\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
lea ecx,
and esp, -16
push DWORD PTR
push ebp
mov ebp, esp
sub esp, 24
mov DWORD PTR , ecx
mov DWORD PTR , ebx
call ___main
mov ebx, DWORD PTR _a
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC8
call _printf
mov DWORD PTR , OFFSET FLAT:LC9
call _puts
mov DWORD PTR , ebx
call _stack1
mov DWORD PTR , OFFSET FLAT:LC10
call _puts
mov DWORD PTR , ebx
mov DWORD PTR , OFFSET FLAT:LC8
call _printf
mov eax, 0
mov ecx, DWORD PTR
mov ebx, DWORD PTR
mov esp, ebp
pop ebp
lea esp,
ret
.globl _a
.data
.align 4
_a:
.long 1
.def _printf; .scl 2; .type 32; .endef
.def _puts; .scl 2; .type 32; .endef



I think it work because of less mov instructions were used to shift data on the stack? Please correct me if I am wrong.



It isn't entirely clear to me what you've done. Changed "sub esp, 40" to "sub esp, 4"??? You're clobbering your stack when you do "mov ", etc. I think. Look closely at why gcc is subtracting 40. I believe it's leaving a "reusable argument area" used for calls to printf, etc. Rather than pushing parameters and cleaning up the stack afterwards, as we might do, gcc has been doing it this way for... a while. Without subtracting "enough" from esp, kaboom! I *think* that's what's happening...

Best,
Frank


Yes, I am trying to understand it that why I am toying around with the ... but it turn out to be unwanted result.

Referring to http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames


void stack1(int c)
{
    /*Local Stack 1 Variable*/
    int e = c;
    printf("Parameter c: %i\nLocal variable e: %i\n", c, e);
   
    printf("Stack 1\n");

    if(e == 1)
    {
        printf("Calling Stack 2\n");

        stack2(e);
    }
    else
    {
        printf("Exiting Stack1()\n");
        printf("Parameter c: %i\nLocal variable e: %i\n", c, e);
    }

    printf("Exiting Stack1()\n");
    printf("Parameter c: %i\nLocal variable e: %i\n", c, e);

}


if the C source code are convert to assembly source code, it should look similar to:


LC4:
.ascii "Parameter c: %i\12Local variable e: %i\12\0"
LC5:
.ascii "Stack 1\0"
LC6:
.ascii "Calling Stack 2\0"
LC7:
.ascii "Exiting Stack1()\0"
.text
.globl _stack1
.def _stack1; .scl 2; .type 32; .endef
_stack1:
push ebp
mov ebp, esp
sub esp, 4

mov eax, DWORD PTR
mov DWORD PTR , eax

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf

mov DWORD PTR , OFFSET FLAT:LC5
call _puts

cmp DWORD PTR , 1
jne L6

mov DWORD PTR , OFFSET FLAT:LC6
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
call _stack2

jmp L7
L6:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf
L7:
mov DWORD PTR , OFFSET FLAT:LC7
call _puts

mov eax, DWORD PTR
mov DWORD PTR , eax
mov eax, DWORD PTR
mov DWORD PTR , eax
mov DWORD PTR , OFFSET FLAT:LC4
call _printf

        add esp, 4
leave
ret
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"


Again correct me if I am wrong.

Thank you.
Posted on 2010-03-11 09:03:34 by deathhex
Well, I wouldn't say you were "wrong", but if you expect gcc to emit code just like your wikibook says, your expectations are incorrect.

The amount gcc subtracts from esp for local variables has always been a mystery. D. J. Delorie (author of the 32-bit dos port of gcc) suggested, in one post, that if you really cared what the rationale was, you could look at the source (he pointed out the specific place in the source). I never cared enough.

As Scali points out, it matters what optimization switch you use (as well as gcc version). If you try "-Os", I think you'll see code closer to what the book says. The vital difference being that arguments to printf, et al, are being pushed on the stack, instead of moved. This allows a smaller amount to be subtracted from esp.

I still don't get what you're trying to do here, deathhex...

Best,
Frank

Posted on 2010-03-11 13:14:13 by fbkotler

Well, I wouldn't say you were "wrong", but if you expect gcc to emit code just like your wikibook says, your expectations are incorrect.

The amount gcc subtracts from esp for local variables has always been a mystery. D. J. Delorie (author of the 32-bit dos port of gcc) suggested, in one post, that if you really cared what the rationale was, you could look at the source (he pointed out the specific place in the source). I never cared enough.

As Scali points out, it matters what optimization switch you use (as well as gcc version). If you try "-Os", I think you'll see code closer to what the book says. The vital difference being that arguments to printf, et al, are being pushed on the stack, instead of moved. This allows a smaller amount to be subtracted from esp.

I still don't get what you're trying to do here, deathhex...

Best,
Frank




I am trying to deal with stack frame (function) and its local variable.

Frank, are you familiar with gdb?

Let said I debug a program a come to a assembly instruction:

mov ax, DWORD PTR // DWORD PTR is a variable

how to I print the content of DWORD PTR using gdb?

print  DWORD PTR is not working for me.

Thanks.
Posted on 2010-03-16 05:17:40 by deathhex


Well, I wouldn't say you were "wrong", but if you expect gcc to emit code just like your wikibook says, your expectations are incorrect.

The amount gcc subtracts from esp for local variables has always been a mystery. D. J. Delorie (author of the 32-bit dos port of gcc) suggested, in one post, that if you really cared what the rationale was, you could look at the source (he pointed out the specific place in the source). I never cared enough.

As Scali points out, it matters what optimization switch you use (as well as gcc version). If you try "-Os", I think you'll see code closer to what the book says. The vital difference being that arguments to printf, et al, are being pushed on the stack, instead of moved. This allows a smaller amount to be subtracted from esp.

I still don't get what you're trying to do here, deathhex...

Best,
Frank




I am trying to deal with stack frame (function) and its local variable.

Frank, are you familiar with gdb?

Let said I debug a program a come to a assembly instruction:

mov ax, DWORD PTR // DWORD PTR is a variable

how to I print the content of DWORD PTR using gdb?

print  DWORD PTR is not working for me.

Thanks.


Sorry for the serious language problem here... must having cognitive problem over here...

Correction:

I am trying to deal with stack frame (function) and its local variable.

Frank, are you familiar with gdb?

Let said I want to debug a program and come across some assembly instruction:

mov ax, DWORD PTR // DWORD PTR is a variable

how do I print the content of DWORD PTR by using gdb?

print  DWORD PTR is not working for me.

Thanks.
Posted on 2010-03-16 05:26:04 by deathhex
I know of gdb, yeah. I don't know about "familiar". We're not close friends.

I prefer a different debugger, Patrick Alken's "Assembly Language Debugger":

http://ald.sf.net

I don't know if that'll work in Cygwin or not...

Rather than try to figure out how to do what you want in gdb, so I can tell you, I'm going to suggest RTFM. Besides the gdb manual itself, there are a number of tutorials about, showing gdb "sessions" to debug code...

http://linuxfocus.berlios.de/English/July2004/article343.shtml

http://www.ffnn.nl/pages/articles/linux/gdb-gnu-debugger-intro.php

http://www.ibm.com/developerworks/linux/library/l-debug/

http://www.ibm.com/developerworks/library/l-gdb/

I've observed that gdb is happier if we include debugging info - "-F dwarf" (dwarf is supposed to be the "native" debug info format for gdb. I've never noticed any difference between "stabs" and "dwarf", to be honest). Also, a "nop" right after your "_start:" label (if it's in your code) seems to help.

Also, gdb reads ".gdbinit" from current or home directory. Chuck Crayne showed us his .gdbinit - good for both 64-bit and 32-bit - I'm sure I saved it, but I can't find it at the moment. :( This one if from Jeff Owens, I think...

All of this is for Linux. I don't know how much of it applies to Cygwin.

Best,
Frank

Attachments:
Posted on 2010-03-16 21:56:13 by fbkotler
in GDB you could print the EBP value by:

x $EBP-n

or

x $EBP+n

where n is an integer value.


Thank you.
Posted on 2010-04-14 09:21:38 by deathhex