I am writing a problem to calculate smallest common multiple in assembly. GDB shows sigsegv exception at the very first line pushl %ebp. Can you tell me how to fix this?
test.c
#include <stdio.h>
extern int nww(int a, int b); // Funkcja z asm
int main()
{
int a = 10, b = 3;
int nw= nww(a,b);
printf("NWW %d i %d = %d ",a,b,nw);
return 0;
}
nww.s
.text
.global nww
.type nww, #function
nww:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl 12(%ebp), %ebx
nwd:
movl $0, %edx # miejsce na reszte
divl %ebx # podziel a przez b, reszta w d
movl %ebx, %eax
movl %edx, %ebx # przygotowanie nastepnego dzielenia
cmp $0, %edx
jnz nww
movl %eax, %edx # NWD do dx
movl 8(%ebp), %eax # nowe A i B
movl 12(%ebp), %ebx
imull %ebx, %eax
divl %edx
exit:
movl %ebp, %esp
popl %ebp
ret
Related
I'm trying to translate from C to assembly two functions, one that sort an array of index and one that find the minimum number starting from an index. When I run the program it works , the new array is sorted but at the end it gives me this error
1 2 3 3 4 6 7
*** stack smashing detected ***: ./invidia terminated
Annullato (core dump creato)
this is my .c file
#include <stdio.h>
#include <stdlib.h>
int* sort(int* v, int dim);
int min(int v[], int dim, int t);
int main(){
int v[] = {1,3,2,4,6,7,3};
int dim = 7,i;
int *c = sort(v,dim);
for (i = 0; i<dim; i++)
printf("%d ", c[i]);
return 0;
}
/*int* sort(int* v, int dim){
int i,j=0,t;
int mino,temp;
for (t = 0; t<dim; t++){
for(i=t;i<dim;i++){
mino = min (v,dim,t); <- min number from index t
if (v[i]==mino){
temp = v[j];
v[j] = v[i];
v[i] = temp;
j++;
break;
}
}
}
return v;
}
int min(int v[], int dim, int t){
int i, min = 1000;
for (i=t; i<dim;i++)
if (v[i]<min)
min = v[i];
return min;
}
*/
and my .s file
.globl sort
sort: #v->ebx dim-> esi i->edi, j->ecx t->edx, mino->eax, temp ->ebp
pushl %ebx
pushl %esi
pushl %edi
pushl %ebp
subl $32, %esp
movl 52(%esp), %ebx
movl 56(%esp), %esi
movl $0, %edi
movl $0, %ecx
movl $0, %eax
movl $0, %edx
movl $0, %ebp
FOR1:
cmpl %esi, %edx
jge EXIT
movl %edx, %edi
FOR2:
cmpl %esi, %edi
jge EXIT2
movl %ebx, (%esp)
movl %esi, 4(%esp)
movl %edx, 8(%esp)
movl %ebx, 12(%esp)
movl %eax, 16(%esp)
movl %ecx, 20(%esp)
movl %edx, 24(%esp)
call min
movl 12(%esp), %ebx
movl 20(%esp), %ecx
movl 24(%esp), %edx
cmpl (%ebx, %edi, 4), %eax
jne PSEUDOEND
movl (%ebx, %ecx, 4), %ebp
movl %esi, 12(%esp)
movl (%ebx, %edi, 4), %esi
movl %esi, (%ebx, %ecx, 4)
movl %ebp, (%ebx, %edi, 4)
movl 12(%esp), %esi
incl %ecx
incl %edx
jmp FOR1
PSEUDOEND:
incl %edi
jmp FOR2
EXIT:
movl %ebx, %eax
popl %ebp
popl %edi
popl %esi
popl %ebx
addl $32, %esp
ret
EXIT2:
incl %edx
jmp FOR1
.globl min
min:
movl 4(%esp), %ecx
movl 8(%esp), %edx
movl 12(%esp), %ebx
movl $1000, %eax
FOR:
cmpl %edx, %ebx
jge END
cmpl %eax, (%ecx, %ebx, 4)
cmovl (%ecx, %ebx, 4), %eax
incl %ebx
jmp FOR
END:
ret
to compile I use
gcc -m32 filename.c filename.s -o filename
I don't think that the problem is in the assembly translation because it prints correctly the new array. What could be the problem?
The assembly functions with commented c version:
/*
int f (int x)
{
return x+2;
}
void map2 (int* one, int * another, int n)
{
int i;
for (i=0; i<n; i++)
*(another+i) = f(*(one+i));
}
*/
.text
.globl f
f:
/********************************** prologue *************************************/
pushl %ebp
movl %esp, %ebp
/********************************************************************************/
movl 8(%ebp), %eax
addl $2, %eax
/************************************* end **************************************/
movl %ebp, %esp
popl %ebp
ret
/*********************************************************************************/
.text
.globl map2
map2:
/********************************** prologue *************************************/
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
/********************************************************************************/
movl $0, %ebx
L1: cmpl $16(%ebp), %ebx // error
jge out
movl $12(%ebp), %esi // error
addl %ebx, %esi
movl $8(%ebp), %edi // error
addl %ebx, %edi
/********************************** calls f *************************************/
pushl %eax
pushl %ecx
pushl %edx
pushl (%edi)
call f
movl %eax, (%esi) /* *(another+i) = f(*(one+i)); */
popl %edx
popl %ecx
popl %eax
/********************************************************************************/
/************************************* end **************************************/
popl %edi
popl %esi
popl %ebx
movl %ebp, %esp
popl %ebp
ret
/********************************************************************************/
I'm getting
fmap2.s:44: Error: junk `(%ebp)' after expression
fmap2.s:47: Error: junk `(%ebp)' after expression
fmap2.s:50: Error: junk `(%ebp)' after expression
Why? There is something to do with having 2 prologues and endings in the same file?
The base-dislocation numbers of those error lines are correct.
According to gcc documentation, you need to remove dollar signs in front of the numeric constants used for displacement:
One point to bear in mind is that, when a constant is used for disp/scale, ’$’ shouldn’t be prefixed.
movl $0, %ebx
L1: cmpl 16(%ebp), %ebx
jge out
movl 12(%ebp), %esi
addl %ebx, %esi
movl 8(%ebp), %edi
addl %ebx, %edi
.file "calc.c"
.text
.globl calc
.type calc, #function
calc:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
movl 16(%ebp), %ecx
leal (%edx,%edx,2), %edx
movl 12(%ebp), %eax
leal (%edx,%eax,2), %eax
movl %ecx, %edx
sall $4, %edx
subl %ecx, %edx
addl %edx, %eax
popl %ebp
ret
.size calc, .-calc
.ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
.section .note.GNU-stack,"",#progbits
I'm trying to understand what's going on with this assembly code. I created it by typing gcc -O1 -S calc.c which generated a calc.s assembly file.
Can someone explain (in terms of the addition and multiplication in calc.c) what is going on, line by line?
The original C code is:
int calc(int x, int y, int z)
{
return 3*x + 2*y + 15*z;
}
Ok, now it does something, I'll annotate it for you
calc:
pushl %ebp ; \
movl %esp, %ebp ; / set up basic stack frame
movl 8(%ebp), %edx ; load x
movl 16(%ebp), %ecx ; load z
leal (%edx,%edx,2), %edx ; calculate x + 2 * x
movl 12(%ebp), %eax ; load y
leal (%edx,%eax,2), %eax ; calculate (x + 2 * x) + (2 * y)
movl %ecx, %edx ; make a temp copy of z
sall $4, %edx ; calculate z * 16
subl %ecx, %edx ; calculate (z * 16) - z
addl %edx, %eax ; calculate final sum
popl %ebp
ret
The C codes is:
int rSum(int *Start, int Count)
{
if (Count <= 0)
return 0;
return *Start + rSum(Start+1, Count-1);
}
the corresponding Assemble codes is:
.file "test98.c"
.text
.globl rSum
.type rSum, #function
rSum:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
cmpl $0, 12(%ebp)
jg .L2
movl $0, %eax
jmp .L3
.L2:
movl 8(%ebp), %eax
movl (%eax), %ebx
movl 12(%ebp), %eax
leal -1(%eax), %edx
movl 8(%ebp), %eax
addl $4, %eax
movl %edx, 4(%esp)
movl %eax, (%esp)
call rSum
leal (%ebx,%eax), %eax
.L3:
addl $20, %esp
popl %ebx
popl %ebp
ret
.size rSum, .-rSum
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",#progbits
I can't understand this instrutions "subl $20, %esp", and Why is $20 ?
subl $20, %esp subtracts 20 from the stack pointer (esp). This allocates 20 bytes of space on the stack that can be used for local variables.
i'm a new one to learn assembly. i write a c file:
#include <stdlib.h>
int max( int c )
{
int d;
d = c + 1;
return d;
}
int main( void )
{
int a = 0;
int b;
b = max( a );
return 0;
}
and i use gcc -S as01.c and create a assembly file.
.file "as01.c"
.text
.globl max
.type max, #function
max:
pushl %ebp
movl %esp, %ebp
subl $32, %esp
movl $0, -4(%ebp)
movl $1, -24(%ebp)
movl $2, -20(%ebp)
movl $3, -16(%ebp)
movl $4, -12(%ebp)
movl $6, -8(%ebp)
movl 8(%ebp), %eax
addl $1, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leave
ret
.size max, .-max
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
subl $20, %esp
movl $0, -4(%ebp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call max
movl %eax, -8(%ebp)
"as01.s" 38L, 638C
i' confused, beacuse movl %eax, -4(%ebp) movl -4(%ebp), %eax in max(),
i know that %eax is used for returning the value of any function.
I think %eax is a temporarily register for store the c + 1.
This is right?
thank you for your answer.
You don't have optimisation turned on, so the compiler is generating really bad code. The primary storage for all your values is in the stack frame, and values are loaded into registers only long enough to do the calculations.
The code actually breaks down into:
pushl %ebp
movl %esp, %ebp
subl $32, %esp
Standard function prologue, setting up a new stack frame, and reserving 50 bytes for the stack frame.
movl $0, -4(%ebp)
movl $1, -24(%ebp)
movl $2, -20(%ebp)
movl $3, -16(%ebp)
movl $4, -12(%ebp)
movl $6, -8(%ebp)
Fill the stack frame with dummy values (presumably as a debugging aid).
movl 8(%ebp), %eax
addl $1, %eax
movl %eax, -4(%ebp)
Read the parameter c out of the stack frame, add one to it, store it into a (different) stack slot.
movl -4(%ebp), %eax
leave
ret
Read the value back out of the stack slot and return it.
If you compile this with optimisation, you'll see most of the code vanish. If you use -fomit-frame-pointer -Os, you should end up with this:
max:
movl 4(%esp), %eax
incl %eax
ret
movl %eax, -4(%ebp)
Here the value computed for d (now stored in eax) is saved in d's memory cell.
movl -4(%ebp), %eax
While here the return value (d's) gets loaded into eax, because, as you know, eax holds functions' return value.
As #David said, you're compiling without optimization, so gcc generates easy-to-debug code, which is quite inefficient and repetitive sometimes.