x86 Assembly Programming: Recursive function is overflowing the stack - recursion

I am trying to code a recursive Fibonacci program in x86 Assembly (Intel AT&T syntax). I get a StackOverflow error in the form of a segmentation fault. Below is my code:
# Function signature:
# int factorial(int n)
.text
.equ n, 8
.equ fibMinus1, -4
.global fibonacci
fibonacci:
# Prologue (prepare the stack frame)
push %ebp
mov %esp, %ebp
# ECX is the non-volatile register which stores n
movl n(%ebp), %ecx
# Make space on the stack frame to store fib(n - 1)
subl $4, %esp
# If n == 0:
cmpl $0, %ecx
# return 0
je retZero
# If n == 1:
cmpl $1, %ecx
# return 1
je retOne
# EDX = fibonacci(n - 1)
decl %ecx
push %ecx
call fibonacci
movl %eax, fibMinus1(%esp)
# EAX = fibonacci(n - 2)
movl n(%ebp), %ecx
subl $2, %ecx
push %ecx
call fibonacci
# fibonacci(n - 1) + fibonacci(n - 2)
addl fibMinus1(%esp), %eax
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
# Return fibonacci(n - 1) + fibonacci(n - 2)
ret
retZero:
movl $0, %eax
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
# Return the maximum possible weight of the bags :D
ret
retOne:
movl $1, %eax
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
# Return the maximum possible weight of the bags :D
ret
This seems strange, considering that I modify the necessary parameters when pushing them onto the stack before the function call, and after each function call, I execute the epilogue sequence to reframe the stack to its proper position such that the proper parameters are retrieved during the next call.
My code models the following Python recursive code:

Related

x86 Assembly: Prologue of recursive function messes up parameters

I am trying to implement Knapsack's algorithm through recursion in x86 Assembly, modeling the following Java code. However, when I run my program, it seems as if the parameter taking in the capacity of the bag (the 4th parameter) is changed following a recursive call (specifically following the prologue).
The initial call is:
knapsack(weights, values, 2, 2, 0)
When I look in the debugger, initially all the parameters are taken in as correctly:
weights is the pointer to the correct array (0x5655b2f0) ($ebp + 8)
values is the pointer to the correct array (0x5655b300) ($ebp + 12)
num_items = 2 ($ebp + 16)
capacity = 2 ($ebp + 20)
cur_value = 0 ($ebp + 24)
However, in the code executed at maximizeItemUsage, I execute the following recursive call:
knapsack(weights, values, 2, 1, 0)
However, when I look at my debugger, after the following line of code in the prologue (in knapsack):
mov %esp, %ebp
I get the following data in the parameters:
0 ($ebp + 8)
2 ($ebp + 12)
1 ($ebp + 16)
0x5655b300 ($ebp + 20)
0x5655b2f0 ($ebp + 24)
This seems quite strange, considering that the prologue is to supposed to align the stack properly. Below is my code:
# Function signature:
# int knapsack(int* w, int* v, int num_items,
# int capacity, int current);
.text
# Define our macros, which store the location of the parameters and values
# relative to the stack's base pointer (EBP)
.equ weights, 8
.equ values, 12
.equ num_items, 16
.equ capacity, 20
.equ cur_value, 24
.equ do_not_use, -4
.equ use, -8
.global knapsack
knapsack:
# solves the knapsack problem
# #weights: an array containing how much each item weighs
# #values: an array containing the value of each item
# #num_items: how many items that we have
# #capacity: the maximum amount of weight that can be carried
# #cur_weight: the current weight
# #cur_value: the current value of the items in the pack
# Prologue (prepare the stack frame)
push %ebp
mov %esp, %ebp
# Make space for local variables on the stack
# 3 variables (4 bytes each)
# Default values are 0
#
# 1. the value of the bag if we DO NOT use the current item
# 2. the value of the bag if we USE the current item
# 3. the maximum value of the bag currently
sub $8, %esp
movl $0, do_not_use(%ebp)
movl $0, use(%ebp)
# Base Case: we have utilized all the items or there is no more space left
# in the bag (num_items = 0 or capacity = 0)
cmpl $0, num_items(%ebp)
jle emptyBag
cmpl $0, capacity(%ebp)
jle emptyBag
# Case 1: We do not use the current element because adding it wil surpass capacity
# weights[n - 1] > capacity
# Push the new parameters in the stack (everything stays the same, except that
# n -> n - 1 since we are no longer using the current element)
# Compute weights[n - 1] (stored in ECX register)
# Get the memory address of the values array
movl weights(%ebp), %ecx
# Move to the memory address of weights[n - 1]
push %edx
movl num_items(%ebp), %edx # num_items
decl %edx # num_items - 1
imul $4, %edx # 4(num_items - 1)
addl %edx, %ecx # m_v + 4(num_items - 1)
# Get the actual value of weights[n - 1]
movl (%ecx), %ecx # Get value at address m_w + 4(num_items - 1)
pop %edx
# If weights[n - 1] > capacity
cmpl %ecx, capacity(%ebp)
# Shift to analyzing the previous items
jl analyzePreviousItems
# Case 2: We can use the current element (in this case, find the maximum of the values
# we use the element or if we do not use the element
jmp maximizeItemUsage
# Solidify the EAX register data
movl %eax, %eax
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
# Return the maximum possible weight of the bags :D
ret
maximizeItemUsage:
# knapsack(weights, values, num_items - 1, capacity, current_value)
# All parameters remain the same (except that n > n - 1)
push weights(%ebp)
push values(%ebp)
# num_items - 1
movl num_items(%ebp), %edx
decl %edx
push %edx
push capacity(%ebp)
push cur_value(%ebp)
# Call knapsack(weights, values, num_items - 1, capacity, cur_value)
call knapsack
# The value if we DO NOT use the current item
movl %eax, do_not_use(%ebp)
# knapsack(weights, values, n - 1, c - weights[n]) + values[n]
# All parameters remain the same (except that n > n - 1 and c > c - weights[n])
push weights(%ebp)
push values(%ebp)
# num_items - 1
movl num_items(%ebp), %edx
decl %edx
# capacity - weights[n] (stored in the ECX register)
# Get the memory address of the values array
movl weights(%ebp), %ecx
# Move to the memory address of weights[n]
push %edx
movl num_items(%ebp), %edx # num_items
imul $4, %edx # 4(num_items)
addl %edx, %ecx # m_w + 4(num_items)
# Restore the value of the EDX register
pop %edx
# Get the actual value of weights[n]
movl (%ecx), %ecx # Get value at address m_w + 4(num_items)
# -weights[n]
neg %ecx
# capacity - weights[n]
addl capacity(%ebp), %ecx
push %ecx
push cur_value(%ebp)
# Call knapsack(weights, values, num_items - 1, capacity - weights[n], cur_value)
call knapsack
# The value if we USE the current item
movl %eax, use(%ebp)
# Compute the maximum value of knapsack(weights, values, num_items - 1, capacity, cur_value)
# and knapsack(weights, values, n - 1, c - weights[n]) + values[n]
movl use(%ebp), %ecx
cmpl %ecx, do_not_use(%ebp)
jl setUseAsMax
movl do_not_use(%ebp), %eax
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
ret
setUseAsMax:
movl use(%ebp), %eax
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
ret
analyzePreviousItems:
# Recursive Call 1: knapsack(weights, values, n - 1, c)
# All parameters remain the same (except that n -> n - 1)
push weights(%ebp)
push values(%ebp)
# We use the EDX to contain the changed parameters since it is a
# non-volatile register
movl num_items(%ebp), %edx
decl %edx
push %edx
push capacity(%ebp)
push cur_value(%ebp)
# Call knapsack(weights, values, num_items - 1, capacity, cur_value)
call knapsack
# The value if we DO NOT use the current item
movl %eax, do_not_use(%ebp)
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
# Return knapsack(weights, values, n - 1, c)
ret
emptyBag:
movl 0, %eax
# Epilogue (cleanup/realign the stack frame)
mov %ebp, %esp
pop %ebp
# Return 0
ret
# 3 variables (4 bytes each)
# Default values are 0
#
# 1. the value of the bag if we DO NOT use the current item
# 2. the value of the bag if we USE the current item
# 3. the maximum value of the bag currently
sub $8, %esp
movl $0, do_not_use(%ebp)
movl $0, use(%ebp)
The comments claim to reserve space for 3 variables (12 bytes) but the code only has sub $8, %esp.
push weights(%ebp)
push values(%ebp)
# num_items - 1
movl num_items(%ebp), %edx
decl %edx
push %edx
push capacity(%ebp)
push cur_value(%ebp)
# Call knapsack(weights, values, num_items - 1, capacity, cur_value)
call knapsack
In all 3 recursive calls you have pushed the arguments in the wrong order!
This is the correct way:
push cur_value(%ebp)
push capacity(%ebp)
movl num_items(%ebp), %edx
decl %edx
push %edx
push values(%ebp)
push weights(%ebp)
call knapsack
push %edx
movl num_items(%ebp), %edx # num_items
imul $4, %edx # 4(num_items)
addl %edx, %ecx # m_w + 4(num_items)
# Restore the value of the EDX register
pop %edx
In the 2nd recursive call, you have 1 argument too few! Why is there a pop %edx ?
# Case 2: We can use the current element (in this case, find the maximum of the values
# we use the element or if we do not use the element
jmp maximizeItemUsage
# Solidify the EAX register data
movl %eax, %eax
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
# Return the maximum possible weight of the bags :D
ret
Please note that the code below the jmp maximizeItemUsage is unreachable. It will never run.
call knapsack # -> %EAX
# The value if we DO NOT use the current item
movl %eax, do_not_use(%ebp)
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
# Return knapsack(weights, values, n - 1, c)
ret
In analyzePreviousItems that movl %eax, do_not_use(%ebp) instruction is silly because the concerned local variable is just about to stop existing.
And an optimization for free
call knapsack
# The value if we USE the current item
movl %eax, use(%ebp)
# Compute the maximum value of knapsack(weights, values, num_items - 1, capacity, cur_value)
# and knapsack(weights, values, n - 1, c - weights[n]) + values[n]
movl use(%ebp), %ecx
cmpl %ecx, do_not_use(%ebp)
jl setUseAsMax
movl do_not_use(%ebp), %eax
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
ret
setUseAsMax:
movl use(%ebp), %eax
# Epilogue (cleanup the stack frame)
mov %ebp, %esp
pop %ebp
ret
This part of your code gets much simpler if you don't reload the use variable to a different register when it is already present in %EAX.
call knapsack
movl %eax, use(%ebp) (*)
cmpl %eax, do_not_use(%ebp)
jl setUseAsMax
movl do_not_use(%ebp), %eax
setUseAsMax:
mov %ebp, %esp
pop %ebp
ret
(*) Here also you don't need to store movl %eax, use(%ebp) because the use variable is about to get terminated.

Attempting to implement this recursive Fibonacci sequence gives wrong outputs

I am trying to implement Fibonacci sequence in assembly by using recursion. This is my first time of trying to implement recursion in x86 Assembly.
The code compiles fine but it gives wrong outputs. The output for 1 is 1, output for 2 is 0, output for 3 is 1, output for 4 is 2, output for 5 is 3.
Only output it gives correct when you plug 5 in.
Is there something wrong with the algorithm?
.DATA
n1 DWORD ?
prompt1 BYTE "Please enter the first value", 0
prompt3 BYTE "No negative numbers!",0
string BYTE 40 DUP (?)
resultLbl BYTE "The Fib is: ", 0
fib BYTE 40 DUP (?), 0
.CODE
_MainProc PROC
input prompt1, string, 40
atod string
test eax, eax
js signed
mov n1, eax
jmp procName
signed:
output prompt3, string
jmp end1
procName:
mov eax, n1
push n1
call fib1
add esp,4
dtoa fib, eax
output resultLbl, fib
end1:
mov eax, 0
ret
_MainProc ENDP
Fib1 proc
PUSH EBP ; save previous frame pointer
MOV EBP, ESP ; set current frame pointer
MOV EAX, [EBP+8] ; get argument N
CMP EAX, 1 ; N<=1?
JA Recurse ; no, compute it recursively
MOV ECX, 1 ; yes, Fib(1)--> 1
JMP exit
Recurse:
DEC EAX ; = N-1
MOV EDX, EAX ; = N-1
PUSH EDX ; save N-1
PUSH EAX ; set argument = N-1
CALL Fib1 ; compute Fib(N-1) to ECX
POP EAX ; pop N-1
DEC EAX ; = N-2
PUSH ECX ; save Fib(N-1)
PUSH EAX ; set argument = N-2
CALL Fib1 ; compute Fib(N-2) to ECX
POP EAX ; = Fib(N-1)
ADD ECX, EAX ; = Fib(N-1)+FIB(N-2)
exit:
MOV ESP,EBP ; reset stack to value at function entry
POP EBP ; restore caller's frame pointer
RET
Fib1 endp
END

Assembly power returning wrong value

I'm trying to let the user enter 2 digits, the first one is the base and the second one the exponent.
These two values are stored correctly. I know this by printing them (this printing code is currently commented out).
However, my loop to calculate the answer of the base^exponent is returning a wrong value.
Can anyone point me in the right direction or even solve my problem?
This is my code:
#/**
#* The pow subroutine calculates powers of natural bases
#* and exponents.
#*
#* Arguments:
#*
#* base - the exponential base
#* exp - the exponent
#*
#* Return value: 'base' raised to the power of 'exp'.
#*/
#int pow( int base, int exp )
# {
# int total = 1;
# while !(exp <= 0){
# total = total * base;
# exp = exp -1;
# }
# return total;
# }
.bss
EXP: .long
BASE: .long
TOTAL: .long
.text
FSTR: .asciz "%d"
PSTR: .asciz "%d\n"
.global main
inout:
pushl %ebp # Prolog: push the base pointer.
movl %esp, %ebp # and copy stack pointer to EBP.
subl $4, %esp # Reserve stack space for variable
leal -4(%ebp), %eax # Load address of stack var in eax
pushl %eax # Push second argument of scanf
pushl $FSTR # Push first argument of scanf
call scanf # Call scanf
movl -4(%ebp), %eax # Move result of scanf from stack to eax
movl %ebp, %esp # Clear local variables from stack.
popl %ebp # Restore caller's base pointer.
ret # return from subroutine.
main:
call inout
movl %eax, BASE
#pushl BASE
#pushl $PSTR
#call printf
call inout
movl %eax, EXP
#pushl EXP
#pushl $PSTR
#call printf
#subl $4, %esp
#leal -4(%ebp), %eax
#movl %eax, TOTAL
movl $1, TOTAL
loop:
cmpl $0, EXP
jle end
movl TOTAL, %eax
mull BASE
movl %eax, TOTAL
decl EXP
jmp loop
end:
pushl %eax
pushl $PSTR
call printf
#addl $4, %esp #\
pushl $0 #- Clean up and exit
call exit #/
Thanks in advance.
One possibility is to single step the code in a debugger and verify that the working registers contain the expected values.

Calculate day number from an unix-timestamp in a math way?

How can i calculate day number from a unix-timestamp, in a mathematical way and without using any functions and in simple math formula.
1313905026 --> 8 (Today 08/21/2011)
A unix timestamp doesn't include leap seconds, so we don't have to worry about that. Here is a branch-less1, loop-less algorithm for getting the y/m/d fields from a unix timestamp:
#include <iostream>
int
main()
{
int s = 1313905026;
int z = s / 86400 + 719468;
int era = (z >= 0 ? z : z - 146096) / 146097;
unsigned doe = static_cast<unsigned>(z - era * 146097);
unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365;
int y = static_cast<int>(yoe) + era * 400;
unsigned doy = doe - (365*yoe + yoe/4 - yoe/100);
unsigned mp = (5*doy + 2)/153;
unsigned d = doy - (153*mp+2)/5 + 1;
unsigned m = mp + (mp < 10 ? 3 : -9);
y += (m <= 2);
std::cout << m << '/' << d << '/' << y << '\n'; // 8/21/2011
}
This outputs:
8/21/2011
As you're not interested in y and m (only in d), you can eliminate the last couple of lines from the above computation.
This algorithm is described in excruciating detail here. The link includes a complete derivation, and unit tests spanning millions of years (which is overkill).
1 Branch-less: What looks like small branches in the algorithm above are optimized away by clang at -O3 on macOS:
__Z14get_day_numberi: ## #_Z14get_day_numberi
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
movslq %edi, %rax
imulq $-1037155065, %rax, %rcx ## imm = 0xFFFFFFFFC22E4507
shrq $32, %rcx
addl %ecx, %eax
movl %eax, %ecx
shrl $31, %ecx
sarl $16, %eax
leal (%rax,%rcx), %edx
leal 719468(%rax,%rcx), %esi
testl %esi, %esi
leal 573372(%rax,%rcx), %eax
cmovnsl %esi, %eax
cltq
imulq $963315389, %rax, %rcx ## imm = 0x396B06BD
movq %rcx, %rsi
shrq $63, %rsi
shrq $32, %rcx
sarl $15, %ecx
addl %esi, %ecx
imull $146097, %ecx, %ecx ## imm = 0x23AB1
movl %eax, %esi
subl %ecx, %esi
subl %eax, %esi
leal 719468(%rsi,%rdx), %eax
movl %eax, %ecx
shrl $2, %ecx
imulq $1506180313, %rcx, %rdx ## imm = 0x59C67CD9
shrq $39, %rdx
movl %eax, %esi
subl %edx, %esi
imulq $963321983, %rcx, %rcx ## imm = 0x396B207F
shrq $43, %rcx
addl %esi, %ecx
movl %eax, %edx
shrl $4, %edx
imulq $7525953, %rdx, %rdx ## imm = 0x72D641
shrq $36, %rdx
subl %edx, %ecx
imulq $1729753953, %rcx, %rsi ## imm = 0x6719F361
shrq $32, %rsi
movl %ecx, %r8d
subl %ecx, %eax
movl %ecx, %edi
movl $3855821599, %edx ## imm = 0xE5D32B1F
imulq %rcx, %rdx
subl %esi, %ecx
shrl %ecx
addl %esi, %ecx
shrl $8, %ecx
imull $365, %ecx, %ecx ## imm = 0x16D
subl %ecx, %r8d
shrl $2, %edi
imulq $1506180313, %rdi, %rcx ## imm = 0x59C67CD9
shrq $39, %rcx
shrq $47, %rdx
addl %r8d, %eax
subl %ecx, %eax
leal (%rax,%rdx), %ecx
leal 2(%rcx,%rcx,4), %esi
movl $3593175255, %edi ## imm = 0xD62B80D7
imulq %rsi, %rdi
shrq $39, %rdi
imull $153, %edi, %edi
subl %edi, %esi
leal 4(%rcx,%rcx,4), %ecx
subl %esi, %ecx
movl $3435973837, %esi ## imm = 0xCCCCCCCD
imulq %rcx, %rsi
shrq $34, %rsi
leal 1(%rax,%rdx), %eax
subl %esi, %eax
popq %rbp
retq
.cfi_endproc
t = unix time
second = t MOD 60
minute = INT(t / 60) MOD 60
hour = INT(t / 60 / 60) MOD 24
days = INT(t / 60 / 60 / 24)
years = INT(days / 365.25)
year = 1970 + years + 1
1970 started with a Thursday so, we can calculate the day of the week:
weekday = (days + 4) MOD 7
If Sunday is day 0. If you want Sunday to be day 1 just add 1.
Now, let's find out how many days we are into the year in question.
days = days - years * 365 - leapdays
Finally, we find the month and day of the month.
IF year MOD 4 = 0 THEN ly = 1 ELSE ly = 0
WHILE month <= 12
month = month + 1
IF month = 2 THEN
DaysInMonth = 28 + NOT(year MOD 4) + NOT(year MOD 100)
+ NOT(year MOD 400)
ELSE
DaysInMonth = 30 + (month + (month < 7)) MOD 2
END IF
IF days > DaysInMonth THEN days = days - DaysInMonth
END WHILE
This assumes Boolean values of TRUE = 1, FALSE = 0, NOT TRUE = 0, and NOT FALSE = 1.
Now we have the year, month, day of the month, hour, minute, and second calculated with adjustments for leap years.
There is no simple formula to do this. You would need to subtract the number of years (accounting for leap years) since the epoch, which would probably require a loop or a discrete calculation of some kind. Then use some type of loop to subtract out the number of seconds in each month for the current year. What you are left with is the number of seconds currently into the month.
I would do something like this.
x = ...//the number of seconds
year = 1970
while (x > /*one year*/){
x = x - /*seconds in january, and march-december*/
if(year % 4 == 0){
x -= /*leapeay seconds in february*/
}else{
x -= /*regular seconds in february*/
}
}
//Then something like this:
if(x > /*seconds in january*/){
x -= /*seconds in january*/
}
if(x > /*seconds in february*/){
x -= /*seconds in january*/
}
.
.
.
//After that just get the number of days from x seconds and you're set.
Edit
I recommend using date functions for simplicity, but here is a possible non-loopy alternative answer in case anyone needs it, or would care to develop it further.
First let t be the current time in seconds since the epoch.
Let F be the number of seconds in four years. That is three regular years and one leap year. That should be: 126230400.
Now if you take away all of the time contributed by F, you will get a remainder: y.
So y = n % F.
There are several cases now:
1. y is less that one year
2. y is less than two years
3. y is less than three years and less than two months
4. y is less than three years and greater than two months
5. y is less than four years
Note that 1972 was a leap year, so if you count up by four from 1970, wherever you left off will be a leap year in two years.
let jan, feb, febLY, mar, may, ..., dec be the number of seconds in each month (you'd need to calculate it out).
d represents the day number of the current month and D represents the number of seconds in a day (86400).
y represents the number of seconds in a regular year, and yLY represents the number of seconds in a leap year.
y = (t % F)
if(y < Y){
if(y > jan){
y -= jan
}
if(y > feb){
y -= feb
}
.
.
.
d = y % D
}
else if(y < 2 * y){
y = y - Y
if(y > jan){
y -= jan
}
if(y > feb){
y -= feb
}
.
.
.
d = y % D
}
else if(y < 2 * y + yLY){
y = y - 2 * Y
if(y > jan){
y -= jan
}
if(y > febLY){
y -= febLY
}
.
.
.
d = y % D
}
else{
y = y - 2 * Y - yLY
if(y > jan){
y -= jan
}
if(y > feb){
y -= feb
}
.
.
.
d = y % D
}
Not tested. Also, since the Earth doesn't spin at EXACTLY 1 rotation / 24 hours, they've occasionally made adjustments to time. You need to do a bit of research factor that in.
In rust :
fn date(mut months_to_shift: i32, timezone_shift: i32) -> String {
months_to_shift = months_to_shift * 2_628_000;
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Before time!")
.as_secs() as f32;
let adjusted_time = ((((timestamp / 31_557_600.0) / 4.0).round() as i32 * 86_400)
+ 604800
+ (timezone_shift * 3600)
+ months_to_shift) as f32
+ timestamp; // 608400 offset for number of days missing - 7 - (???) + leap year days +/- timezone shift from EST -- Using timezone shift in my project but not necessary
let years = (1970.0 + (adjusted_time / 31_536_000.0)) as i32;
let mut months = ((adjusted_time % 31_536_000.0) / 2_628_000.0) as i32;
months = if months == 0 { 12 } else { months };
let days = ((adjusted_time % 2_628_000.0) / 86_400.0) as i32;
years.to_string() + "-" + &months.to_string() + "-" + &days.to_string()
}

Qt Creator Assembly Output - LEA instruction [duplicate]

This question already has answers here:
What's the purpose of the LEA instruction?
(17 answers)
Closed 7 years ago.
Qt shows me assembler (x86) command this way:lea (%edx,%eax,1),%ecx
What does it means? I can't find description of this instruction that fits.
UPD
Thanks. So, am i correct?
0) movl $0x0,-0x14(%ebp)
1) mov -0x14(%ebp),%eax
2) inc %eax
3) mov %eax,-0x14(%ebp)
4) mov -0x14(%ebp),%eax
5) inc %eax
6) mov %eax,-0x14(%ebp)
7) mov -0x14(%ebp),%edx
8) mov -0x14(%ebp),%eax
9) lea (%edx,%eax,1),%ecx
10) mov %ecx,-0x14(%ebp)
11) inc %edx
12) mov %edx,-0x14(%ebp)
13) inc %eax
14) mov %eax,-0x14(%ebp)
Makes this("i" is "-0x14(%ebp)"):
0) i=0
1) eax=0
2) eax=1
3) i=1
4) eax=1
5) eax=2
6) i=2
7) edx=2
8) eax=2
9) ecx=2; ecx=4
10) i=4
11) edx=3
12) i=3
13) eax=3
14) i=3
LEA stands for Load Effective Address. It's used to perform an address computation, but then rather than accessing the value at that address it stores the computed address in the destination register.
In this case, it's storing the value of EDX + (EAX * 1) into ECX. This is an alternative to the two-instruction sequence
movl %edx, %ecx
addl %eax, %ecx

Resources