intel x86 - why does -4(%ebp) refers to nothing? - c

In many examples when I compile a c-function (such as the sorting algorithm shell sort) the stackaddress (i gues it is called?) ebp-4 / -4(%ebp) / [ebp]-4 or whatever, which, as I understand, is usually used for the first local variable, is not used in my case.
So I was wondering if someone knows what it is used for, as it is not used for any local variables, or anything else for that matter.
Furthermore, 20 is subtracted from the stack pointer to allocate stack space for the locale variables - but then a value is still saved to -24(%ebp) - how is that possible when there is only made room until -20??
the c-function lookes like this:
void shellsort(int a[], unsigned int n) {
unsigned int gap, i, j;
for (gap = n / 2; gap > 0; gap = gap == 2 ? 1 : 5 * gap / 11) {
for (i = gap; i < n; i++) {
int tmp = a[i];
for (j = i; j >= gap && tmp < a[j - gap]; j -= gap)
a[j] = a[j - gap];
a[j] = tmp;
}
}
}
And this is my stack using the gcc -S 32-bit Ubuntu
12(%ebp) = n
8(%ebp) = a[]
-8(%ebp) = tmp
-12(%ebp) = j
-16(%ebp) = i
-20(%ebp) = gap
-24(%ebp) = (gap * 4) + gap
Thanks in advance :)

There are two parts to your question.
The first as I understand it has to do with what [EBP-4] is used for. For that, I recommend you read a summary of the x86 stack frame at What is stack frame in assembly?.
To properly answer the whole 20/24 part of your question, we need to look at the disassembled code. The following is an extract from the disassembly of the C code you provided.
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp /* (1) */
.cfi_def_cfa_register 5
pushl %ebx /* (2) */
subl $20, %esp /* (3) */
movl 12(%ebp), %eax
shrl %eax
movl %eax, -20(%ebp)
jmp .L2
.cfi_offset 3, -12
I have identified the three (3) key lines in the disassembled output above.
At (1), the base pointer is being set to the stack pointer. As per the information supplied in the link earlier, this is just part of setting up the stack frame.
At (2), we are saving EBX (a non-volatile register) to the stack. This automatically updates ESP (but not EBP), subtracting four from its current value. Note that after this operation, EBP = ESP + 4.
At (3), we are subtracting 20 from ESP. After this operation, EBP = ESP + 24.
That is why it is safe to access [EBP-20].
Hope this helps.

On the x86 ebp is typically used as the frame pointer and esp is the stack pointer. Around the frame pointer the frame pointer of the caller and the return address are saved. That could explain the gap. In my assembly actually -4(%ebp) is used, so maybe we are looking at a different ABI, but there should always be a gap for the stack administration.
About the -20 subtracted from the stack pointer and still access -24(%ebp): there is probably a push after the movl %esp, %ebp in your assembly, which would account for an additional 4 bytes.

Related

Question about omitting the return statement in a function declaration

Consider the following code for producing a list of numbers from 0 to 9 along with values of 2 and -3 raised to the power of the corresponding number from the list:
#include <stdio.h>
int power(int m, int n);
main()
{
int i;
for (i = 0; i <= 10; ++i)
printf("%d %d %d\n", i, power(2, i), power(-3, i));
return 0;
}
int power(int base, int n)
{
int i, p;
p = 1;
for (i = 1; i <= n; ++i)
p = p * base;
// return statement purposefully omitted. //
}
Of course the program does not work properly without the return statement for the power function, however by running the written code I get the following output:
0 1 1
1 2 2
2 3 3
3 4 4
4 5 5
5 6 6
6 7 7
7 8 8
8 9 9
9 10 10
And I'm wondering where are the numbers in the second and third column of the output coming from? In lack of a valid return value of power, the control transfers back to the calling function, but why does it output these numbers?
As pointed out by #dyukha and #Daniel H, the value returned is "whatever is in your EAX register". Your function finishes on a for-loop, hence the last instruction realized before returning (ending the function) probably was a branching test, to check if i <= n (your loop condition). You can actually check on what variable is set to your EAX register by using your compiler to generate the assembly version of your code (option -S). You may try to follow what values are set into your register before the call to
popq %rbp
retq
at the end of your function.
On my computer, I tried with Apple LLVM version 9.0.0 (clang-900.0.39.2), which generate the following for my function:
movl %edi, -8(%rbp)
movl %esi, -12(%rbp)
movl $1, -20(%rbp)
movl $1, -16(%rbp)
LBB2_1: ## =>This Inner Loop Header: Depth=1
movl -12(%rbp), %eax
cmpl -16(%rbp), %eax
jl LBB2_4
## BB#2: ## in Loop: Header=BB2_1 Depth=1
movl -20(%rbp), %eax
imull -8(%rbp), %eax
movl %eax, -20(%rbp)
## BB#3: ## in Loop: Header=BB2_1 Depth=1
movl -16(%rbp), %eax
addl $1, %eax
movl %eax, -16(%rbp)
jmp LBB2_1
LBB2_4:
movl -4(%rbp), %eax
popq %rbp
retq
As you can see, I have 4 remarkable addresses: -8(%rbp), -12(%rbp), -16(%rbp) and -20(%rbp). Given the order of declaration in the C code, and the order of initialisation, -8(%rbp) is base, -12(%rbp) is n, -16(%rbp) is i and -20(%rbp) is p.
LBB2_1 is your loop condition. The instructions for the check are
* move value of n in %eax
* is the value of %eax lower then the value of i, store the result in %eax
* if %eax says that it was lower, go to label LBB2_4 else continue to next instruction
The three instructions after BB#2 are you actual multiplication. The three instructions after BB#3 are your increment of i, which is followed by an unconditional jump to your loop condition at label LBB2_1.
The ending of the power function is to take whatever is in memory address -4(%rbp), tu put it in %eax, and then leave the function (reset stack pointer, put value in %eax to the proper variable in the previous stack frame).
In the code produced by my compiler, I don't see the same result as you do, as I get every time the last two columns equal to 0 (-4(%rbp) is never set to anything). Except when adding a call to another function foo, taking two integers as parameters, having two local integer variables (to ensure that my new stack frame will be the same size as the power function one). This function actually set the address -4(%rbp). When calling my function right before entering the loop, I effectively find the value from -4(%rbp) as set in my function foo returned in my function power.
As a colleague just told me, playing with undefined behaviour is dangerous as your compiler is allowed to treat it any way it likes. It could be summoning a demon for what it's worth.
In definitive, or TL;DR, this undefined behaviour is handle in some way by the compiler. Whether some value is moved from one local variable, defined or not, or nothing special is moved to the register %eax is up to the compiler. Anyway, whatever was hanging in there, got returned when retq is called.

LEAL and MOVL in machine instruction

what is the difference between following machine codes??
movl 8(%ebp), %ecx
leal 8(%ebp), %ecx
can someone explain this to me???
The first fetches the 32 bit value pointed to by 8(%ebp).
The latter computes the flat address.
Thus, in C, given int x = 0; and it is located at 8(%ebp) (i.e. x is in the stack frame of the function):
The first is int y = x;
The latter is int *z = &x;
In machine code [for most/many architectures, such as x86--but not all (e.g. mc68000)] registers are the same regardless of whether they contain a value or address.

Finding the dimensions of an array through assembly

I have an assignment to reverse engineer the assembly to find the values of R, S, and T in the following code. Assume that R, S, and T are constants declared with #define.
long int A[R][S][T];
int store_ele(int h, int i, int j, long int *dest)
{
A[h][i][j] = *dest;
return sizeof(A);
}
When compiling this program, GCC generates the following assembly code (with -O2):
store_ele:
movslq %esi, %rsi //%rsi = h
movslq %edi, %rdi //%rdi = i
movq (%rcx), %rax //moves the value from %rcx to %rax
leaq (%rdi,%rdi,4), %rdi //%rdi = 4 * i + i
leaq (%rsi,%rsi,4), %rcx //%rcx = 4 * h + h
movslq %edx, %rdx //%rdx = j
leaq (%rcx,%rdi,4), %rcx //%rcx = 4 * %rdi + %rcx = 4 * (4 * i + i) + (4 * h + h)
addq %rcx, %rdx //adds something to j
movq %rax, A(,%rdx,8) //moves some value
movl $1120, %eax //%eax = 1120
ret //returns %eax
I want to ask if what I am understanding about the assembly is right and any tips or assistance is appreciated!
Edit: I don't know what it is called but our prof. defines movq: source, destination and other similar assembly instructions where the first argument is source and second is destination
Edit 2: Biggest issue is how do I find the values of the three constants just based on the assembly. I think
movq %rax, A(,%rdx,8) //moves some value
movl $1120, %eax //%eax = 1120
ret //returns %eax
Is going to play the main role in finding out what it does but I don't know what to do with it.
Edit 3: Don't know if I should put the answers, but if someone might have same problem, I got T = 5, S = 4, and R = 7 where R = 1120/T*S*8 and I got T and S from matching coefficients from the help I got from this thread.
That's x86-64 AT&T syntax (mnemonic source, dest), with the x86-64 System V ABI (first arg in rdi, see this approximate summary of that calling convention, or find links to better ABI docs (including the official standards) in the x86 tag wiki).
What you're calling "functions" are assembly instructions. Each one assembles to a single machine instruction.
Hint: your comments are wrong about which arg is which. Check the ABI for arg-passing order.
Since you know the declaration is long int A[R][S][T]:
A[h][i][j] is equivalent to *(A[h][i] + j), where A[h][i] is an array type (with size [T]). Applying this recursively, A[h][i][j] is equivalent to *(base_pointer + S*T*h + T*i + j) (where base_pointer is just a long*, for the purposes of C pointer math which implicitly scales by sizeof(long) in this case).
You seem to be on the right track working out how the LEAs are multiplying, so you can find T, then use that to find S (by dividing the factor for h).
Then to find R, look at the function return value, which is R*S*T * sizeof(long).
sizeof(long) in the x86-64 System V ABI is 8 bytes. The offset into the array is scaled by 8 bytes, too, of course, so don't forget to factor that out when getting your S and T values.

Given Assembly, translate to C

I am originally given the function prototype:
void decode1(int *xp, int *yp, int *zp)
now i am told to convert the following assembly into C code:
movl 8(%ebp), %edi //line 1 ;; gets xp
movl 12(%ebp), %edx //line 2 ;; gets yp
movl 16(%ebp),%ecx //line 3 ;; gets zp
movl (%edx), %ebx //line 4 ;; gets y
movl (%ecx), %esi //line 5 ;; gets z
movl (%edi), %eax //line 6 ;; gets x
movl %eax, (%edx) //line 7 ;; stores x into yp
movl %ebx, (%ecx) //line 8 ;; stores y into zp
movl %esi, (%edi) //line 9 ;; stores z into xp
These comments were not given to me in the problem this is what I believe they are doing but am not 100% sure.
My question is, for lines 4-6, am I able to assume that the command
movl (%edx), %ebx
movl (%ecx), %esi
movl (%edi), %eax
just creates a local variables to y,z,x?
also, do the registers that each variable get stored in i.e (edi,edx,ecx) matter or can I use any register in any order to take the pointers off of the stack?
C code:
int tx = *xp;
int ty = *yp;
int tz = *zp;
*yp = tx;
*zp = ty;
*xp = tz;
If I wasn't given the function prototype how would I tell what type of return type is used?
Let's focus on a simpler set of instructions.
First:
movl 8(%ebp), %edi
will load into the EDI register the content of the 4 bytes that are situated on memory at 8 eight bytes beyond the address set in the EBP register. This special EBP usage is a convention followed by the compiler code generator, that per each function, saves the stack pointer ESP into the EBP registers, and then creates a stack frame for the function local variables.
Now, in the EDI register, we have the first parameter passed to the function, that is a pointer to an integer, so EDI contains now the address of that integer, but not the integer itself.
movl (%edi), %eax
will get the 4 bytes pointed by the EDI register and load them into the EAX register.
Now in EAX we have the value of the integer pointed by the xp in the first parameter.
And then:
movl %eax, (%edx)
will save this integer value into the memory pointed by the content of the EDX register which was in turn loaded from EBP+12 which is the second parameter passed to the function.
So, your first question, is this assembly code equivalent to this?
int tx = *xp;
int ty = *yp;
int tz = *zp;
*yp = tx;
*zp = ty;
*xp = tz;
is, yes, but note that there are no tx,ty,tz local variables created, but just processor registers.
And your second question, is no, you can't tell the type of return, it is, again, a convention on the register usage that you can't infer just by looking at the generated assembly code.
Congratulations, you got everything right :)
You can use any register but some need to be preserved, that is they should be saved before use and restored afterwards. In typical calling conventions you can use eax, ecx and edx, the rest need to be preserved. The assembly you showed doesn't include code to do this, but presumably it is there.
As for the return type, that's hard to deduce. Simple types are returned in the eax register, and something is always in there. We can't tell if that's intended as a return value, or just remains of a local variable. That is, if your function had return tx; it could be the same assembly code. Also, we don't know the type for eax either, it could be anything that fits in there and is expected to be returned there according to the calling convention.

C Code represented as Assembler Code - How to interpret?

I got this short C Code.
#include <stdint.h>
uint64_t multiply(uint32_t x, uint32_t y) {
uint64_t res;
res = x*y;
return res;
}
int main() {
uint32_t a = 3, b = 5, z;
z = multiply(a,b);
return 0;
}
There is also an Assembler Code for the given C code above.
I don't understand everything of that assembler code. I commented each line and you will find my question in the comments for each line.
The Assembler Code is:
.text
multiply:
pushl %ebp // stores the stack frame of the calling function on the stack
movl %esp, %ebp // takes the current stack pointer and uses it as the frame for the called function
subl $16, %esp // it leaves room on the stack, but why 16Bytes. sizeof(res) = 8Bytes
movl 8(%ebp), %eax // I don't know quite what "8(%ebp) mean? It has to do something with res, because
imull 12(%ebp), %eax // here is the multiplication done. And again "12(%ebp).
movl %eax, -8(%ebp) // Now, we got a negative number in front of. How to interpret this?
movl $0, -4(%ebp) // here as well
movl -8(%ebp), %eax // and here again.
movl -4(%ebp), %edx // also here
leave
ret
main:
pushl %ebp // stores the stack frame of the calling function on the stack
movl %esp, %ebp // // takes the current stack pointer and uses it as the frame for the called function
andl $-8, %esp // what happens here and why?
subl $24, %esp // here, it leaves room for local variables, but why 24 bytes? a, b, c: the size of each of them is 4 Bytes. So 3*4 = 12
movl $3, 20(%esp) // 3 gets pushed on the stack
movl $5, 16(%esp) // 5 also get pushed on the stack
movl 16(%esp), %eax // what does 16(%esp) mean and what happened with z?
movl %eax, 4(%esp) // we got the here as well
movl 20(%esp), %eax // and also here
movl %eax, (%esp) // what does happen in this line?
call multiply // thats clear, the function multiply gets called
movl %eax, 12(%esp) // it looks like the same as two lines before, except it contains the number 12
movl $0, %eax // I suppose, this line is because of "return 0;"
leave
ret
Negative references relative to %ebp are for local variables on the stack.
movl 8(%ebp), %eax // I don't know quite what "8(%ebp) mean? It has to do something with res, because`
%eax = x
imull 12(%ebp), %eax // here is the multiplication done. And again "12(%ebp).
%eax = %eax * y
movl %eax, -8(%ebp) // Now, we got a negative number in front of. How to interpret this?
(u_int32_t)res = %eax // sets low 32 bits of res
movl $0, -4(%ebp) // here as well
clears upper 32 bits of res to extend 32-bit multiplication result to uint64_t
movl -8(%ebp), %eax // and here again.
movl -4(%ebp), %edx // also here
return ret; //64-bit results are returned as a pair of 32-bit registers %edx:%eax
As for the main, see x86 calling convention which may help making sense of what happens.
andl $-8, %esp // what happens here and why?
stack boundary is aligned by 8. I believe it's ABI requirement
subl $24, %esp // here, it leaves room for local variables, but why 24 bytes? a, b, c: the size of each of them is 4 Bytes. So 3*4 = 12
Multiples of 8 (probably due to alignment requirements)
movl $3, 20(%esp) // 3 gets pushed on the stack
a = 3
movl $5, 16(%esp) // 5 also get pushed on the stack
b = 5
movl 16(%esp), %eax // what does 16(%esp) mean and what happened with z?
%eax = b
z is at 12(%esp) and is not used yet.
movl %eax, 4(%esp) // we got the here as well
put b on the stack (second argument to multiply())
movl 20(%esp), %eax // and also here
%eax = a
movl %eax, (%esp) // what does happen in this line?
put a on the stack (first argument to multiply())
call multiply // thats clear, the function multiply gets called
multiply returns 64-bit result in %edx:%eax
movl %eax, 12(%esp) // it looks like the same as two lines before, except it contains the number 12
z = (uint32_t) multiply()
movl $0, %eax // I suppose, this line is because of "return 0;"
yup. return 0;
Arguments are pushed onto the stack when the function is called. Inside the function, the stack pointer at that time is saved as the base pointer. (You got that much already.) The base pointer is used as a fixed location from which to reference arguments (which are above it, hence the positive offsets) and local variables (which are below it, hence the negative offsets).
The advantage of using a base pointer is that it is stable throughout the entire function, even when the stack pointer changes (due to function calls and new scopes).
So 8(%ebp) is one argument, and 12(%ebp) is the other.
The code is likely using more space on the stack than it needs to, because it is using temporary variables that could be optimized out of you had optimization turned on.
You might find this helpful: http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames
I started typing this as a comment but it was getting too long to fit.
You can compile your example with -masm=intel so the assembly is more readable. Also, don't confuse the push and pop instructions with mov. push and pop always increments and decrements esp respectively before derefing the address whereas mov does not.
There are two ways to store values onto the stack. You can either push each item onto it one item at a time or you can allocate up-front the space required and then load each value onto the stackslot using mov + relative offset from either esp or ebp.
In your example, gcc chose the second method since that's usually faster because, unlike the first method, you're not constantly incrementing esp before saving the value onto the stack.
To address your other question in comment, x86 instruction set does not have a mov instruction for copying values from memory location a to another memory location b directly. It is not uncommon to see code like:
mov eax, [esp+16]
mov [esp+4], eax
mov eax, [esp+20]
mov [esp], eax
call multiply(unsigned int, unsigned int)
mov [esp+12], eax
Register eax is being used as an intermediate temporary variable to help copy data between the two stack locations. You can mentally translate the above as:
esp[4] = esp[16]; // argument 2
esp[0] = esp[20]; // argument 1
call multiply
esp[12] = eax; // eax has return value
Here's what the stack approximately looks like right before the call to multiply:
lower addr esp => uint32_t:a_copy = 3 <--. arg1 to 'multiply'
esp + 4 uint32_t:b_copy = 5 <--. arg2 to 'multiply'
^ esp + 8 ????
^ esp + 12 uint32_t:z = ? <--.
| esp + 16 uint32_t:b = 5 | local variables in 'main'
| esp + 20 uint32_t:a = 3 <--.
| ...
| ...
higher addr ebp previous frame

Resources