Calling assembly function from c leads to segmentation fault - c

This is my assembly program add.s
.globl add
add:
movl 4(%esp), %eax
movl 8(%esp), %ebx
addl %ebx, %eax
ret
This is my C program. I am trying to call the assembly program from the C program.
#include <stdio.h>
int add(int a, int b);
int main() {
int res = add(5,6);
printf("%d",res);
return 0;
}
But the above code gives me a segmentation fault. What is causing this error and how do I fix it?

Assuming the cdecl calling convention, you are using the ebx register which is supposed not to be clobbered: its value has to be saved and then restored by the callee if it is going to be modified.
The caller assumes that ebx is not going to change by calling a function. Therefore if the callee modifies ebx it has to save it first and then restore it to its original value before returning from the function.
The registers eax, ecx and edx can be used without having to save them first and then restored. Therefore, I would recommend replacing ebx with edx in your code:
add:
movl 4(%esp), %eax
movl 8(%esp), %edx
addl %edx, %eax
ret

Related

Segmentation fault in assembly when multiplying registers?

I was trying to convert the following C code into assembly. Here is the C code:
typedef struct {
int x;
int y;
} point;
int square_distance( point * p ) {
return p->x * p->x + p->y * p->y;
}
My assembly code is as follows:
square_distance:
.LFB23:
.cfi_startproc
movl (%edi), %edx
imull %edx, %edx
movl 4(%edi), %eax
imull %eax, %eax
addl %edx, %eax
ret
.cfi_endproc
I get a segmentation fault when I try to run this program. Could someone please explain why? Thanks! I would be grateful!
Your code is 32 bit code (x86) but you apply the calling convention used with 64 bit code (x64). This can obviously not work.
The x86 calling convention is passing all parameters on the stack.
The x64 calling convention is passing the first parameter in rdi, the second in rsi, the third in rdx, etc. (I'm not sure which registers are used if there are more than 3 parameters, this might also depend on your platform).
Your code is presumably more or less correct for x64 code, that would be something like this:
square_distance:
movl (%rdi), %edx
imull %edx, %edx
movl 4(%rdi), %eax
imull %eax, %eax
addl %edx, %eax
ret
With x86 code the parameters are passed on the stack and the corresponding correct code would be something like this:
square_distance:
movl 4(%esp), edx
movl (%edx), eax
imull eax, eax
movl 4(%edx), edx
imull edx, edx
addl edx, eax
ret
In general the Calling conventions subject is vast, there are other calling conventions depending on the platform and even within the same platform different calling conventions can exist in certain cases.
Just want to supplement Jabberwocky answer. Because my reputation is not enough to comment.
The way of passing paraments when calling functions (also known as calling convention) are different from architectures and operating systems(OS). You can find out many common calling conventions from this wiki
From the wiki we can know that The x64 calling convention on *nix is passing the first six parameters through RDI, RSI, RDX, RCX, R8, R9 registers, while others through stack.

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.

C/Assembly Subprogram Segmentation fault

Trying to run through GDB and keep getting a segmentation fault once the C main program enters the main function.
GDB Error:
Breakpoint 1, main () at binom_main.c:7
7 n=10;
(gdb) s
10 0;
(gdb) s
12 +){
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x00000000004005c4 in otherwise ()
(gdb)
I compiled the code as such:
as binom.s -o binom.o
gcc -S -Og binom_main.c
gcc -c binom_main.s
gcc binom_main.o binom.o -o runtimes
I'm trying to learn how to use GDB more efficiently here but segfaults like these are pretty ambiguous and limiting. Why is this segfault being caused the moment the function begins? Have I linked the two files incorrectly?
Main :
#include <stdio.h>
unsigned int result,m,n,i;
unsigned int binom(int,int);
int main(){
n=10;
i=0;
for (i=1; i<2;i++){
result = binom(n,i);
printf("i=%d | %d \n", i, result );
}
return 0;
}
Sub:
.text
.globl binom
binom:
mov $0x00, %edx #for difference calculation
cmp %edi, %esi #m=n?
je equalorzero #jump to equalorzero for returning of value 1
cmp $0x00, %esi #m=0?
je equalorzero
cmp $0x01, %esi #m=1?
mov %esi,%edx
sub %edi, %edx
cmp $0x01, %edx # n-m = 1 ?
je oneoronedifference
jmp otherwise
equalorzero:
add $1, %eax #return 1
call printf
ret
oneoronedifference:
add %edi, %eax #return n
ret
otherwise:
sub $1, %edi #binom(n-1,m)
call binom
sub $1, %esi #binom(n-1,m-1)
call binom
ret
When you use gdb to debug asm, look at the disassembly window as well as the source window. (e.g. layout asm / layout reg, and layout next until you get the combo of windows that you want.) See the bottom of the x86 tag wiki for some more tips and a link to docs.
You can use stepi (si) to step by instructions, not by C statements, while investigating a crash outside your asm, caused by it corrupting something before returning.
This looks like a bug:
sub $1, %edi #binom(n-1,m)
call binom
# at this point, %edi no longer holds n-1, and %esi no longer holds m.
# because binom clobbers them. (This is normal)
# as Jester points out, you also don't save the return value (%eax) from the first call anywhere.
sub $1, %esi #binom(n-1,m-1)
call binom
Another (minor?) bug is:
cmp $0x01, %esi #m=1?
# but then you never read the flags that cmp set
Another serious bug:
equalorzero:
add $1, %eax #return 1 # wrong: nothing before this set %eax to anything.
# mov $1, %eax # You probably want this instead
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.

Translate C code to assembly code?

I have to translate this C code to assembly code:
#include <stdio.h>
int main(){
int a, b,c;
scanf("%d",&a);
scanf("%d",&b);
if (a == b){
b++;
}
if (a > b){
c = a;
a = b;
b = c;
}
printf("%d\n",b-a);
return 0;
}
My code is below, and incomplete.
rdint %eax # reading a
rdint %ebx # reading b
irmovl $1, %edi
subl %eax,%ebx
addl %ebx, %edi
je Equal
irmov1 %eax, %efx #flagged as invalid line
irmov1 %ebx, %egx
irmov1 %ecx, %ehx
irmovl $0, %eax
irmovl $0, %ebx
irmovl $0, %ecx
addl %eax, %efx #flagged as invalid line
addl %ebx, %egx
addl %ecx, %ehx
halt
Basically I think it is mostly done, but I have commented next to two lines flagged as invalid when I try to run it, but I'm not sure why they are invalid. I'm also not sure how to do an if statment for a > b. I could use any suggestions from people who know about y86 assembly language.
From what I can find online (1, 2), the only supported registers are: eax, ecx, edx, ebx, esi, edi, esp, and ebp.
You are requesting non-existent registers (efx and further).
Also irmov is for moving an immediate operand (read: constant numerical value) into a register operand, whereas your irmov1 %eax, %efx has two register operands.
Finally, in computer software there's a huge difference between the character representing digit "one" and the character representing letter "L". Mind your 1's and l's. I mean irmov1 vs irmovl.
Jens,
First, Y86 does not have any efx, egx, and ehx registers, which is why you are getting the invalid lines when you pour the code through YAS.
Second, you make conditional branches by subtracting two registers using the subl instruction and jumping on the condition code set by the Y86 ALU by ways of the jxx instructions.
Check my blog at http://y86tutoring.wordpress.com for details.

Resources