Hi everyone. I am writing a code that receives two numbers and puts them into strings. The first number works fine, but when the program tries to get the second number, it crashes. I found out that the problem is with "12(%ebp)."

If I change it to 8(%ebp) or 16(%ebp), the program works. Can anyone tell me why that is?

This is my main function:

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

extern void getlarge(char *number1, char *number2, char *result);
int main(int argc, char *argv[])
{
  unsigned char number1[256];
  unsigned char number2[256];
  unsigned char result[256];
  getlarge(number1, number2, result);
  printf("done\n");
  system("PAUSE");	
  return 0;
}

Assembly function:

.section .data
numberone:
          .ascii "Enter first number: \n"
          .byte 00
numbertwo:
          .ascii "Enter second number: \n"
          .byte 00
formatstr:
          .ascii  "%s"
          .byte 00
.text
          .align 4

.global _getlarge
_getlarge:
          pushl %ebp
          movl %esp, %ebp
          call _getnumberone
          call _getnumbertwo
          movl %ebp, %esp
          popl %ebp
          ret

.global _getnumberone
_getnumberone:
    pushl %ebp
    movl %esp, %ebp
    pushl $numberone
    call _printf
    addl $4, %esp
    movl 8(%ebp), %ebx
    pushl %ebx
    pushl $formatstr
    call _scanf
    addl $8, %esp
    movl %ebp, %esp
    popl %ebp
    ret
    
.global _getnumbertwo
_getnumbertwo:
    pushl %ebp
    movl %esp, %ebp
    pushl $numbertwo
    call _printf
    addl $4, %esp
    movl 12(%ebp), %ecx //crashes with 12(%ebp) works with 8 or 16
    pushl %ecx
    pushl $formatstr
    call _scanf
    addl $8, %esp
    movl %ebp, %esp
    popl %ebp
    ret

Thank you.

Edited 5 Years Ago by LMat619: n/a

Hi,
Please, can you tell me what are you looking for reading the stack. You must realize that inside the stack with the parameters there are the returning addresses of your procedures (segment and offset 8 bytes) and you call one procedure from another one that is called from a C function (3 calls * 8 bytes). If you want access to the parameters, you can add to esp the required value and call your procedure (restoring esp).
Cheers.

Hi,
I was wrong. Actualy there are two calls.
Inside _getlarge the first parameter is at ebp+8 (return segment and offset)
Inside _getnumbertwo the first parameter passed to _getlarge is at ebp+16. (return segment and offset of _getlarge and return segment and offset of _getnumbertwo).
In a call instruction the segment and the offset of the return address are pushed on the stack.
Remenber to correct _getnumberone also.
And I remenber to you that with the C calling convention you can change inside your procedure only eax, ecx and edx. The rest of register must be preserved, with push and pop.
Cheers.

Hi once more,

You can compare your code with the next one:

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

extern "C" void getlarge(unsigned char *number1, unsigned  char *number2, unsigned  char *result);
int main(int argc, char *argv[])
{
  unsigned char number1[256];
  unsigned char number2[256];
  unsigned char result[256];
  getlarge(number1, number2, result);
  printf("done,\n 1 = %s,\n 2 = %s\n", number1, number2);
  system("PAUSE");	
  return 0;
}

And obviously, the assembly code:

.section .data
numberone:
          .ascii "Enter first number: \n"
          .byte 00
numbertwo:
          .ascii "Enter second number: \n"
          .byte 00
formatstr:
          .ascii  "%s"
          .byte 00
.text
          .align 4

.global _getlarge
_getlarge:
          pushl %ebp
          movl %esp, %ebp
          call _getnumberone
          call _getnumbertwo
          movl %ebp, %esp
          popl %ebp
          ret

.global _getnumberone
_getnumberone:
    pushl %ebp
    movl %esp, %ebp
    pushl $numberone
    call _printf
    addl $4, %esp
    movl 16(%ebp), %ecx
    pushl %ecx
    pushl $formatstr
    call _scanf
    addl $8, %esp
    movl %ebp, %esp
    popl %ebp
    ret
    
.global _getnumbertwo
_getnumbertwo:
    pushl %ebp
    movl %esp, %ebp
    pushl $numbertwo
    call _printf
    addl $4, %esp
    movl 20(%ebp), %ecx
    pushl %ecx
    pushl $formatstr
    call _scanf
    addl $8, %esp
    movl %ebp, %esp
    popl %ebp
    ret

Keep in mind that every 'call' decrements esp by 8 bytes.

Cheers.

This article has been dead for over six months. Start a new discussion instead.