Factorial Function in Assembly - c

So I'm trying to create a factorial function in assembler
In c:
#include<stdio.h>
int fat (int n)
{
if (n==0) return 1;
else return n*fat(n-1);
}
int main (void){
printf("%d\n", fat(4));
return 0;
}
In Assembly:
.text
.global fat
fat:push %ebp
mov %esp, %ebp
movl $1,%eax
movl 4(%ebp),%edx
LOOP:cmp $0,%edx
je FIM
sub $1,%edx
push %edx
call fat
imul %edx,%eax
FIM:mov %ebp, %esp
pop %ebp
ret
I keep getting the segmentation fault error and I don't know why...can someone help me?

The offset is probably wrong in this line:
movl 4(%ebp),%edx
The stack has the previous value of %ebp and the return address already, so your offset is going to have to be more than 4.
I recommend stepping through the assembly code with the debugger, and make sure that all the register values are exactly what you expect them to be. You will also have problems with the %edx register across calls unless you save and restore its value, too.

fat:push %ebp
mov %esp, %ebp
movl $1,%eax
movl 4(%ebp),%edx /* Must be 8(%ebp) because of the return address! */
LOOP:cmp $0,%edx
je FIM
sub $1,%edx
push %edx
call fat /* The call to fat() just trashed edx, oops. Gotta save/restore it! */
imul %edx,%eax /* The result will be in edx, but you need to return it in eax! */
/* Why isn't "push %edx" compensated here with "pop" or "addl $4,%esp"??? */
FIM:mov %ebp, %esp
pop %ebp
ret
Rewriting your C function, assemblyish style, may be helpful:
int fat (int n)
{
int eax, edx, savedEdx;
eax = 1;
edx = n; /* n = %8(%ebp) */
if (edx == 0)
goto done;
savedEdx = edx; /* can do this with pushl %edx */
--edx;
eax = fat(edx); /* pushl %edx; call fat; addl $4, %esp or popl %edx */
edx = savedEdx; /* popl %edx */
eax *= edx; /* can do this with imul %edx */
done:
return eax;
}

Related

Explanation of array accessing in X86 assembly

I have the following C function:
int sum_arr(int b[], int size){
int counter = size-1;
int res = 0;
while(counter >= 0){
res = res + b[counter];
counter = counter - 1;
}
return res;
}
From which I generated the following assembly code using:
gcc -Og -S file.c
Out came the following assembly code (I have included the parts of interest only):
sum_arr:
.LFB41:
.cfi_startproc
subl $1, %esi
movl $0, %eax
jmp .L2
.L3:
movslq %esi, %rdx
addl (%rdi,%rdx,4), %eax
subl $1, %esi
.L2:
testl %esi, %esi
jns .L3
rep ret
.cfi_endproc
I am having some trouble with .L3. The way I understand it is that it starts off by moving the int counter from a 32 bit register %esi into a 64 bit register %rdx. Then I don't understand the following line:
addl (%rdi,%rdx,4), %eax
in particluar the (%rdi,%rdx,4) part, which gets added to the value in the %eax register.
And on the last line it decrements the counter with 1.
Could someone help me out with that part?
.L3:
movslq %esi, %rdx /* sign extend counter<%esi> to 64bit %rdx */
addl (%rdi,%rdx,4), %eax /* res<%eax> += b<%rdi>[counter<%rdx>]; */
subl $1, %esi /* counter<%esi> -= 1 */
.L2:
testl %esi, %esi /* do counter<%esi> & counter<%esi> */
jns .L3 /* if result is no 0, jump to L3 */
Basically addl (%rdi,%rdx,4), %eax is where you access the array (%rdi) with the index of counter (%rdx) and add the value of the element to res (%eax), the 4 is just the multiply of counter (%rdx) for the memory access as each address in the int array consume 4 bytes in memory in your system.
The line basically says res += MEMORY[addrssOf(b) + counter*4]
BTW, I believe you want to check that size > 0 before line int counter = size-1;, and also as P__J__ mentioned in his answer, your res can overflow as it have the same type of each element in the array you summing.
in this form it is easier to understand:
sum_arr:
sub esi, 1
js .L4
movsx rsi, esi
mov eax, 0
.L3:
add eax, DWORD PTR [rdi+rsi*4]
sub rsi, 1
test esi, esi
jns .L3
ret
.L4:
mov eax, 0
ret
Two remarks:
your integer is very likely to overflow so you should use long long as temporary & return value. It can be shortened as well
long long sum_arr(const int *b, size_t size){
long long res = 0;
while(size--){
res = res + *b++;
}
return res;
}

Converting my function to assembly from C

Hi I have a function in C that returns the max of a set of numbers in an array. I need to convert it into assembly and make it callable from C. nums is the array in which all the numbers are stored. len is the length of the array that was passed. The other variables that I made are local variables
.global max
.text
.equ word_size, 4
max:
#prologue
push %ebp
movl %esp, %ebp
.equ nums, 2*word_size
.equ len, 3*word_size
.equ cur_max, 4*word_size
.equ index, 5*word_size
#eax is index
#short cur_max = nums[0]
movl cur_max(%ebp), %eax
movl $0, %ebx
mov nums(%ebp), %edx
leal (%edx, %ebx, word_size), %edx
mov %edx, cur_max(%ebp)
#for(index = 1; index < len;index++)
mov index(%ebp), %eax
mov len(%ebp), %ebx
mov nums(%ebp), %ecx
mov cur_max(%ebp), %edx
mov $1, %eax
for_loop_begin:
cmp %ebx, %eax
jl loop_begin
jmp for_loop_end
loop_begin:
if_loop:
leal (%ecx,%eax,word_size), %esi #nums[i] = esi
cmp %edx,%esi
jg in_if_loop
in_if_loop_end:
inc %eax
jmp for_loop_begin
for_loop_end:
mov %edx,%eax
ret
in_if_loop:
mov %esi,%edx
movl %ebp, %esp
pop %ebp
jmp in_if_loop_end
This is the C code
short max(short* nums, int len){
int index;
short cur_max = nums[0];
for( index = 1; index < len; index++)
if( nums[index] > cur_max)
cur_max = nums[index];
return cur_max;
}

Why this asm code not doubling the value the pointer points

I am trying to interface c code with asm.
But it is not working correctly and I am not able to find the problem.
program.c
#include<stdio.h>
int *asm_multi(int *ptr);
int main()
{
int i=10;
int *p=&i;
asm_multi(p);
printf("%d\n",*p);
return 0;
}
code.asm
.section .text
.global asm_multi
.type asm_multi,#function
asm_multi:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%eax
movl %eax,%edx
leal (%edx,%edx,1),%edx
movl %edx,%eax
movl %ebp,%esp
popl %ebp
ret
I am creating the final executable by
as code.asm -o code.o
gcc program.c code.o -o output
./output
The output it prints is :10 whereas I am expecting: 20
What is the problem in the code? Don't consider the efficiency of the program. I have just started asm programming.
I created above code after reading from a more complex example kept at this link. This works perfectly.
You should learn to use a debugger as soon as possible. It not only helps you find bugs, but also allows you to exactly see what the cpu is doing at each instruction and you can compare that to your intentions.
Also, comment your code, especially when asking for help, so we can tell you where the instructions don't match your intentions, if you were unable to do so yourself.
Let's comment your code then:
asm_multi:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%eax # fetch first argument, that is p into eax
movl %eax,%edx # edx = p too
leal (%edx,%edx,1),%edx # edx = eax + edx = 2 * p
movl %edx,%eax # eax = edx = 2 * p
movl %ebp,%esp
popl %ebp
ret
As you can see, there are two problems:
You are doubling the pointer not the value it points to
You are not writing it back into memory, just returning it in eax which is then ignored by the C code
A possible fix:
asm_multi:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%eax # fetch p
shll $1, (%eax) # double *p by shifting 1 bit to the left
# alternatively
# movl (%eax), %edx # fetch *p
# addl %edx, (%eax) # add *p to *p, doubling it
movl %ebp,%esp
popl %ebp
ret

ATT Assembly to C

Working on learning assembler and I have the following code I have to translate to C:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
imull $886836204, %eax, %edx
movl 8(%ebp), %eax
addl %edx, %eax
addl $629084528, %eax
popl %ebp
ret
I know that it takes two arguments and is in the format int func(int1, int2) {} and it returns something from the addition and multiplication lines. Other than that I'm lost. What does this look like in C?
I'd say int func(int a, int b){return b*886836204+a+629084528;}
I'm pretty sure it's a one line return because it doesnt allocate memory on stack for local variables , but the logic seens to be like this:
int function(int x, int y){
int eax;
int edx;
eax = x;
edx = 886836204 * eax;
eax = y;
eax = eax + edx;
eax = eax + 629084528;
return eax;
}
Something like this:
return x * 886836204 + (x + y) + 629084528;

executing assembly within a function in c++

long getesp() {
__asm__("movl %esp,%eax");
}
void main() {
printf("%08X\n",getesp()+4);
}
why does esp points to value before the stack frame is setup and does it makes any difference between with the code below?
void main() {
__asm__("movl %esp,%eax");
}
After i did a gcc -S file.c
getesp:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
#APP
# 4 "xxt.c" 1
movl %esp,%eax
# 0 "" 2
#NO_APP
leave
ret
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
call getesp
addl $4, %eax
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
addl $20, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
The getesp has a pushl which manipulates the esp and gets the manipulated esp in eax with the inline and as well as in ebp.
Making a function call to fetch the stack pointer and getting it inside the main is definitely different, and it differs by 12 bytes (in this specific case). This is because when you execute the call pushes the eip (if not intersegment, and for linux/unix normal program execution it is only eip) (need citation), next inside the getesp function there is another push with ebp and after that the stack pointer is subtracted by 4. Because the eip and ebp are of 4 bytes, so the total difference is now 12 bytes. Which actually we can see in the function call version.
Without the function call there is no pushing of eip and other esp manipulation, so we get the esp value after the main setup.
I am not comfortable with AT&T so here is the same code in Intel syntax and an Intex syntax asm dump below. Note that in the printf call for the __asm__ inside the main value got into a there is no push or other esp modification so, the __asm__ inside main gets the esp value which was set in the main by the sub esp, 20 line. Where as the value we get by calling getesp is the (what you are expecting) - 12 , as described above.
The C Code
#include <stdio.h>
int a;
long getesp() {
__asm__("mov a, esp");
}
int main(void)
{
__asm__("mov a,esp");
printf("%08X\n",a);
getesp ();
printf("%08X\n",a);
}
The output is in my case for the specific run:
BF855D00
BF855CF4
The intel syntax dump is:
getesp:
push ebp
mov ebp, esp
sub esp, 4
#APP
# 7 "xt.c" 1
mov a, esp
# 0 "" 2
#NO_APP
leave
ret
main:
lea ecx, [esp+4]
and esp, -16
push DWORD PTR [ecx-4]
push ebp
mov ebp, esp
push ecx
sub esp, 20
#APP
# 12 "xt.c" 1
mov a,esp
# 0 "" 2
#NO_APP
mov eax, DWORD PTR a
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:.LC0
call printf
call getesp
mov eax, DWORD PTR a
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:.LC0
call printf
add esp, 20
pop ecx
pop ebp
lea esp, [ecx-4]
ret
I hope this helps.

Resources