Segmentation fault when calling assembly function from C code - c

I'm trying to link assembly functions to a C code for exercise.
Here's my assembly function, written in x86 assembly:
.code32
.section .text
.globl max_function
.type max_function, #function
# i parametri saranno in ordine inverso a partire da 8(%ebp)
max_function:
pushl %ebp # save ebp
movl %esp, %ebp # new frame function
movl $0, %edi # first index is 0
movl 8(%ebp), %ecx # ecx is loaded with the number of elements
cmpl $0, %ecx # check that the number of elements is not 0
je end_function_err #if it is, exit
movl 12(%ebp),%edx # edx is loaded with the array base
movl (%edx), %eax # first element of the array
start_loop:
incl %edi #increment the index
cmpl %edi,%ecx #if it's at the end quit
je loop_exit
movl (%edx,%edi,4),%ebx #pick the value
cmpl %ebx,%eax #compare with actual maximum value
jle start_loop #less equal -> repeat loop
movl %ebx,%eax #greater -> update value
jmp start_loop #repeat loop
loop_exit:
jmp end_function #finish
end_function: #exit operations
movl %ebp, %esp
popl %ebp
ret
end_function_err:
movl $0xffffffff, %eax #return -1 and quit
jmp end_function
It basically defines a function that finds the maximum number of an array (or it should be)
And my C code:
#include <stdio.h>
#include <stdlib.h>
extern int max_function(int size, int* values);
int main(){
int values[] = { 4 , 5 , 7 , 3 , 2 , 8 , 5 , 6 } ;
printf("\nMax value is: %d\n",max_function(8,values));
}
I compile them with gcc -o max max.s max.c.
I get a SegmentationFault when executing the code.
My suspect is that I don't access the value in a right manner, but I can't see why, even because I based my code on an example code that prints argc and argv values when called from the command line.
I'm running Debian 8 64-bit

The problems were:
not preserving %ebx and %edi
not compiling for 32 bit (had to use -m32 flag for gcc)
cmpl operands were inverted
Thanks everybody, problem is solved.
I'll focus more on debugging tools to (disassembling and running step by step was very useful)!

Related

Calling C function from the x86 assembler

I am trying to write a function that converts decimal numbers into binary in assembler. Since printing is so troublesome in there, I have decided to make a separate function in C that just prints the numbers. But when I run the code, it always prints '0110101110110100'
Heres the C function (both print and conversion):
void printBin(int x) {
printf("%d", x);
}
void DecToBin(int n)
{
// Size of an integer is assumed to be 16 bits
for (int i = 15; i >= 0; i--) {
int k = n >> i;
printBin(k & 1);
}
heres the code in asm:
.globl _DecToBin
.extern _printBin
_DecToBin:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp),%eax
movl $15, %ebx
cmpl $0, %ebx
jl end
start:
movl %ebx, %ecx
movl %eax, %edx
shrl %cl, %eax
andl $1, %eax
pushl %eax
call _printBin
movl %edx, %eax
dec %ebx
cmpl $0, %ebx
jge start
end:
movl %ebp, %esp
popl %ebp
ret
Cant figure out where the mistake is. Any help would be appreciated
disassembled code using online program
Your principle problem is that it is very unlikely that %edx is preserved across the function call to printBin.
Also:
%ebx is not a volatile register in most (any?) C calling convention rules. You need to check your compilers documentation and conform to it.
If you are going to use ebx, you need to save and restore it.
The stack pointer needs to be kept aligned to 16 bytes. On my machine (macos), it SEGVs under printBin if you don’t.

Count how many 1 there are in the odd positions of an array of 32-bit numbers

I'm implementing a simple assembly function called through a program in c, to count how many 1 there are in the odd position of an array in 32 bits. The first argument passed to the function is the pointer to the array while the second the number of elements. I do not understand what it does go to infinite loop.
// Assembly code
.globl ones_in_odds
.type ones_in_odds,#function
ones_in_odds:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%ecx
movl 12(%ebp),%esi
#xorl %edi,%edi
xorl %eax,%eax
subl $-1,%esi
startloop:
cmpl $0,%esi
jl endloop
movl (%ecx,%esi,4),%edx
xorl %edi,%edi
innerloop:
cmpl $16,%edi
jg startloop
shrl %edx
shrl %edx
adcl $00,%eax
incl %edi
jmp innerloop
decl %esi
jmp startloop
endloop:
movl %ebp,%esp
popl %ebp
ret
// C Code
#include <stdio.h>
#define DIM 5
int ones_in_odds(int *,size_t);
int main(){
int array[DIM] = {1,3,4,5,6};
int one = ones_in_odds(array,DIM);
printf("Il numero di 1 nelle posizioni dispari e' %d\n",one);
return 0;
}
This adds 1 to ESI:
subl $-1,%esi
It's like the term ESI = ESI - (-1). You want to transform the count of items (DIM) to the index of the last item in array. Thus the count has to be subtracted by 1 or added by (-1). However, you don't need this transformation at this place. Remove the line.
Because of
jg startloop
you don't reach decl %esi and therefore the break condition jl endloop will never been met.
Move decl %esi to the beginning of startloop and you solve also the transformation problem above.
As #Jester mentions, you have to follow the C calling convention since the assembly procedure is a function of the C program. The function is allowed to change EAX, ECX, and EDX ("caller saved") and has to return all other registers unchanged ("callee saved"). The function changes ESI and EDI, but should returm them unchanged. So push them at the beginning of the function and pop them at the end.

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

Segmentation Fault when getting the max of three numbers in Assembly x86

I am trying to get the max of three numbers using C to call a method in Assembly 32 bit AT & T. When the program runs, I get a segmentation fault(core dumped) error and cannot figure out why. My input has been a mix of positive/negative numbers and 1,2,3, both with the same error as a result.
Assembly
# %eax - first parameter
# %ecx - second parameter
# %edx - third parameter
.code32
.file "maxofthree.S"
.text
.global maxofthree
.type maxofthree #function
maxofthree:
pushl %ebp # old ebp
movl %esp, %ebp # skip over
movl 8(%ebp), %eax # grab first value
movl 12(%ebp), %ecx # grab second value
movl 16(%ebp), %edx # grab third value
#test for first
cmpl %ecx, %eax # compare first and second
jl firstsmaller # first smaller than second, exit if
cmpl %edx, %eax # compare first and third
jl firstsmaller # first smaller than third, exit if
leave # reset the stack pointer and pop the old base pointer
ret # return since first > second and first > third
firstsmaller: # first smaller than second or third, resume comparisons
#test for second and third against each other
cmpl %edx, %ecx # compare second and third
jg secondgreatest # second is greatest, so jump to end
movl %eax, %edx # third is greatest, move third to eax
leave # reset the stack pointer and pop the old base pointer
ret # return third
secondgreatest: # second > third
movl %ecx, %eax #move second to eax
leave # reset the stack pointer and pop the old base pointer
ret # return second
C code
#include <stdio.h>
#include <inttypes.h>
long int maxofthree(long int, long int, long int);
int main(int argc, char *argv[]) {
if (argc != 4) {
printf("Missing command line arguments. Instructions to"
" execute this program:- .\a.out <num1> <num2> <num3>");
return 0;
}
long int x = atoi(argv[1]);
long int y = atoi(argv[2]);
long int z = atoi(argv[3]);
printf("%ld\n", maxofthree(x, y, z)); // TODO change back to (x, y, z)
}
The code is causing a segmentation fault because it is trying to jump back to an invalid return address when the ret instruction is executed. This happens for all three different ret instructions.
The reason why it is occurring is because you don't pop the old base pointer before returning. A small change to the code will remove the fault. Change each ret instruction to:
leave
ret
The leave instruction will do the following:
movl %ebp, %esp
popl %ebp
Which will reset the stack pointer and pop the old base pointer that you saved.
Also, your comparisons are not doing what they are specified to do in the comments. When you do:
cmp %eax, %edx
jl firstsmaller
The jump will happen when %edx is smaller than %eax. So you want the code be
cmpl %edx, %eax
jl firstsmaller
which will jump when %eax is smaller than %edx, as specified in the comment.
Reference this this page for details on the cmp instruction in AT&T/GAS syntax.
You forgot to pop ebp before returning from the function.
Also, cmpl %eax, %ecx compares ecx to eax not the other way. So the code
cmpl %eax, %ecx
jl firstsmaller
will jump if ecx is smaller than eax.

Infinite loop in my simple assembly program

I am learning loops and jumps in assembly and I try to make a simple loop. I want the printf command to be called 10 times. I have set the counter variable to 1. I have also set %edx to 1 and then I increment it for every iteration. If it is equal to 10, then we should exit the loop. But now the loop is infinite. I have debugged with gdb and %edx seems to be overwritten in the printf function. That is why I push %edx to the stack and the pop it back after the printf call, but it doesn't work. What have I missed?
.section .data
output:
.asciz "Value is %d\n"
val1:
.int 123
counter:
.int 1
.section .text
.globl _start
_start:
nop
movl counter, %edx # start at 1
gohere:
movl val1, %ebx # move value 123 to %ebx
pushl %edx # push %edx to stack
pushl %ebx # push %ebx to stack
pushl $output
call printf # call printf
popl %edx # pop %edx value
inc %edx
cmp $10, %edx # if %edx is less than 10...
jl gohere # ... go to gohere, otherwise exit
movl $0, %ebx
movl $1, %eax
int $0x80
you pushed output as the last push so the first pop will pop output. it is Stack and it is LIFO. in your code output will be in edx after you pop it.
to solve it put two pops before popl edx:
popl output
popl ebx

Resources