Why does this function allocate more stack space than it needs to, before calling gets()?
echo:
pushl %ebp
movl %esp, %ebp
pushl %ebx
leal -8(%ebp), %ebx
subl $20, %esp <-- Why so much space?
movl %ebx, (%esp)
call gets
...
The corresponding C code:
void echo()
{
char buf[4];
gets(buf);
puts(buf);
}
Why is there an additional extra space of three words between the buffer and the argument for gets?
There are two sentences in the book Computer Systems.
"gcc adhere to an x86 programming guideline that the total stack space used by the function should be multiple of 16 bytes." and "Including the 4 bytes for the saved %ebp and the 4 bytes for the return address,"
Related
I have an assemble code of a function. I have just one local integer variable in it, but my compiler reserve space for 24 byte. Can I resize per hand the memory to be 4 byte (not 24 byte), which are minimum required for the Stack Frame?
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $0, -12(%ebp) //int i = 0;
P.S: I am working on 32 bit on linux
I want to make a function in assembler to be called from c that will write a byte(char) to the file. Here is how function should look in c:
void writebyte (FILE *f, char b)
{
fwrite(&b, 1, 1, f);
}
And here is the code that will call it:
#include <stdio.h>
extern void writebyte(FILE *, char);
int main(void) {
FILE *f = fopen("test.txt", "w");
writebyte(f, 1);
fclose(f);
return 0;
}
So far I came up with following assembler code:
.global writebyte
writebyte:
pushl %ebp
movl %esp, %ebp #standard params
pushl 12(%ebp) # pushing byte to the stack
pushl $1
pushl $1
pushl 8(%ebp) #file to write
call fwrite
popl %ebp
ret
I keep getting from gdb:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0xffa9702c in ?? ()
How do I write such a function in assembly?
EDIT: I am using Ubuntu 16.04
According to cdecl convention, you should push the arguments in reverse order. So f should go first and b should go last. Also the stack should be cleaned up by the caller after calling fwrite().
As noted in the comments, b will be received as value, but we need to pass it to fwrite() as pointer. The pointer will be equal to the value of ebp + 12.
This seems to work for me:
.global writebyte
writebyte:
//create new stack frame
pushl %ebp
movl %esp, %ebp
//push the four arguments to stack (in reverse order)
pushl 8(%ebp)
pushl $1
pushl $1
//get pointer of "b" argument (%ebp+12) and move it to %eax
leal 12(%ebp), %eax
pushl %eax
//call fwrite()
call fwrite
//remove arguments from stack and pop %ebp
leave
ret
I read the textbook "Computer Systems A programmer's perspective". It gives an example program:
/* read input line and write it back */
void echo(){
char buf[8]; /* way too small !*/
gets(buf);
puts(buf);
}
The assembly code for this is:
1 echo:
2 pushl %ebp
3 movl %esp, %ebp
4 pushl %ebx
5 subl $20, %esp
6 leal -12(%ebp), %ebx
7 movl %ebx, (%esp)
8 call gets
9 movl %ebx, (%esp) // This does not look useful for me
10 call puts
11 addl $20, %esp
12 popl %ebx
13 popl %ebp
14 ret
Line 9 seems useless here since line 7 has already store buf at the top of the stack. Then it calls gets. When gets return, buf will be at the top of the stack.
My question is:
Is line 9 useless here?
EDIT: This is Linux.
My question is: Is line 9 useless here?
No. You cannot assume that gets will not change the value on the stack. It is its argument and it is allowed to modify it.
%ebx on the other hand is callee-save. The gets function has to preserve it.
when you are calling the gets function, it may happen that it can modify the values of arguments(%ebx in your case). since you have not mentioned the other part of your code, can't say about that..but its good to store the buff into stack top again,after a function call..
I am trying to learn some assembly code, so I read in some tutorial that the assembly code for
int proc(void)
{
int x,y;
scanf("%x %x", &y, &x);
return x-y;
}
is
1 proc:
2 pushl %ebp
3 movl %esp, %ebp
4 subl $40, %esp
5 leal -4(%ebp), %eax
6 movl %eax, 8(%esp)
7 leal -8(%ebp), %eax
8 movl %eax, 4(%esp)
9 movl $.LC0, (%esp)
10 call scanf
Diagram stack frame at this point
11 movl -4(%ebp), %eax
12 subl -8(%ebp), %eax
13 leave
14 ret
If I well understood, the instructions of line 5 to 8 store some addresses that will be used to store the values of scanf's input. So is it right to say that scanf uses systematically the address %esp plus a certain number of bytes (depending on the sizeof the input) to fetch the address at which is the data will be stored ?
What's happening here is that a stack frame is built up to pass arguments to scanf. subl is used to allocate space for the new stack frame and the movl is used with offsets from the stack pointer, %esp, to write values for the arguments on the freshly allocated stack frame.
A more thorough explanation on x86 calling conventions and cdecl in particular can be found here. Understanding the high-level structure of the stack frame and the cdecl convention will help you make sense of the intent of this code snippet.
Calling convention of scanf is cdecl. It passes its arguments to stack pointed by esp.
#include <stdio.h>
int main(int argc, char * argv[])
{
argv[1][2] = 'A';
return 0;
}
Here is the corresponding assembly code from GCC for a 32-bit Intel architecture. I can't totally understand what is going on.
main:
leal 4(%esp), %ecx - Add 4 to esp and store the address in ecx
andl $-16, %esp - Store first 28 bits from esp's address into esp??
pushl -4(%ecx) - Push the old esp on stack
pushl %ebp - Preamble
movl %esp, %ebp
pushl %ecx - push old esp + 4 on stack
movl 4(%ecx), %eax - move ecx + 4 to eax. this is the address of argv. argc stored at (%ecx).
addl $4, %eax - argv[1]
movl (%eax), %eax - argv[1][0]
addl $2, %eax - argv[1][2]
movb $65, (%eax) - move 'A'
movl $0, %eax - move return value (0)
popl %ecx - get old value of ecx
leave
leal -4(%ecx), %esp - restore esp
ret
What is going on in the beginning of the code before the preamble? Where is argv store according to the following code? On the stack?
The funny code (the first two lines) that you are seeing is the alignment of the stack to 16 bytes (-16 is the same as ~15, and x & ~15 rounds x to a multiple of 16).
argv would be stored at ESP + 8 when entering the function, what leal 4(%esp), %ecx does is create a pointer to a pseudo-struct containing argc and argv, then it proceeds to access them from there. movl 4(%ecx), %eax access argv from this pseudo-struct.
argv is a parameter to "main()", so in many ABIs, it will indeed be passed on the stack.