I just started learning Assembler, and I'm stuck at the very beginning - I'm trying to call a simple function - in fact it's mostly copied from a book, and I keep getting segmentation fault. Maybe someone more experienced could point out what's wrong with this code:
.code32
SYSEXIT = 1
.data
.text
.globl _start
_start:
push $28 #just some random argument
push $33
call myfunc
mov $SYSEXIT, %eax
#exit code is stored in ebx after calling function
int $0x80
.type myfunc, #function
myfunc:
push %ebp #save old base pointer on a stack
movl %esp, %ebp
movl 8(%ebp), %ebx #first argument to ebx
movl 12(%ebp), %ecx #second argument to ecx
addl %ecx, %ebx #add arguments together - store them in ebx
movl %ebp, %esp
pop %ebp
ret
Your function expects the arguments to be longs (32-bit), so you should push them with pushl rather than push.
You should also make sure that you balance the stack after the function returns. I.e. something like:
pushl $28
pushl $33
call myfunc
addl $8,%esp # "removes" two 32-bit arguments off the stack
Related
This question already has answers here:
When do we create base pointer in a function - before or after local variables?
(2 answers)
What is exactly the base pointer and stack pointer? To what do they point?
(6 answers)
Closed last month.
I'm trying to pass some arguments into a function but it doesn't get them correctly. I want to multiply some matrices and I want to pass: address of matrix 1, address of matrix 2, address of the matrix i want the result to be in, and the size of the matrix.
matrix_mult:
pushl %ebp
pushl %ebx
pushl %edi
pushl %esi
movl %esp, %ebp
movl 8(%ebp), %edi
movl 12(%ebp), %esi
movl 16(%ebp), %ebx
movl 20(%ebp), %ecx
*the rest of the algorithm*
After those lines, the values in edi, esi, ebx, ecx are all wrong.
The function calling looks like this - trying to multiply matrix by itself and storing the result into matrix2. The matrix and msizze are stored correctly.
main:
*reading msize and matrix*
pushl msize
pushl $matrix2
pushl $matrix
pushl $matrix
call matrix_mult
addl $16, %esp
In the debugger it shows me that:
edi = 2
esi = big negative value
ebx = big positive value
ecx = big positive value
I'm starting to read LLVM docs and IR documentation.
In common architectures, an asm cmp instruction "result" value is -at least- 3 bits long, let's say the first bit is the SIGN flag, the second bit is the CARRY flag and the third bit is the ZERO flag.
Question 1)
Why the IR icmp instruction result value is only i1? (you can choose only one flag)
Why doesn't IR define, let's call it a icmp2 instruction returning an i3 having SIGN,CARRY and ZERO flags?
This i3 value can be acted upon with a switch instruction, or maybe a specific br2 instruction, like:
%result = cmp2 i32 %a, i32 %b
br2 i3 %result onzero label %EQUAL, onsign label %A_LT_B
#here %a GT %b
Question 2)
Does this make sense? Could this br2 instruction help create new optimizations? i.e. remove all jmps? it is necessary or the performance gains are negligible?
The reason I'm asking this -besides not being an expert in LLVM- is because in my first tests I was expecting some kind of optimization to be made by LLVM in order to avoid making the comparison twice and also avoid all branches by using asm conditional-move instructions.
My Tests:
I've compiled with clang-LLVM this:
#include <stdlib.h>
#include <inttypes.h>
typedef int32_t i32;
i32 compare (i32 a, i32 b){
// return (a - b) & 1;
if (a>b) return 1;
if (a<b) return -1;
return 0;
}
int main(int argc, char** args){
i32 n,i;
i32 a,b,avg;
srand(0); //fixed seed
for (i=0;i<500;i++){
for (n=0;n<1e6;n++){
a=rand();
b=rand();
avg+=compare(a,b);
}
}
return avg;
}
Output asm is:
...
mov r15d, -1
...
.LBB1_2: # Parent Loop BB1_1 Depth=1
# => This Inner Loop Header: Depth=2
call rand
mov r12d, eax
call rand
mov ecx, 1
cmp r12d, eax
jg .LBB1_4
# BB#3: # in Loop: Header=BB1_2 Depth=2
mov ecx, 0
cmovl ecx, r15d
.LBB1_4: # %compare.exit
# in Loop: Header=BB1_2 Depth=2
add ebx, ecx
...
I expected (all jmps removed in the inner loop):
mov r15d, -1
mov r13d, 1 # HAND CODED
call rand
mov r12d, eax
call rand
xor ecx,ecx # HAND CODED
cmp r12d, eax
cmovl ecx, r15d # HAND CODED
cmovg ecx, r13d # HAND CODED
add ebx, ecx
Performance difference (1s) seems to be negligible (on a VM under VirtualBox):
LLVM generated asm: 12.53s
hancoded asm: 11.53s
diff: 1s, in 500 millions iterations
Question 3)
Are my performance measures correct? Here's the makefile and the full hancoded.compare.s
makefile:
CC=clang -mllvm --x86-asm-syntax=intel
all:
$(CC) -S -O3 compare.c
$(CC) compare.s -o compare.test
$(CC) handcoded.compare.s -o handcoded.compare.test
echo `time ./compare.test`
echo `time ./handcoded.compare.test`
echo `time ./compare.test`
echo `time ./handcoded.compare.test`
hand coded (fixed) asm:
.text
.file "handcoded.compare.c"
.globl compare
.align 16, 0x90
.type compare,#function
compare: # #compare
.cfi_startproc
# BB#0:
mov eax, 1
cmp edi, esi
jg .LBB0_2
# BB#1:
xor ecx, ecx
cmp edi, esi
mov eax, -1
cmovge eax, ecx
.LBB0_2:
ret
.Ltmp0:
.size compare, .Ltmp0-compare
.cfi_endproc
.globl main
.align 16, 0x90
.type main,#function
main: # #main
.cfi_startproc
# BB#0:
push rbp
.Ltmp1:
.cfi_def_cfa_offset 16
push r15
.Ltmp2:
.cfi_def_cfa_offset 24
push r14
.Ltmp3:
.cfi_def_cfa_offset 32
push r12
.Ltmp4:
.cfi_def_cfa_offset 40
push rbx
.Ltmp5:
.cfi_def_cfa_offset 48
.Ltmp6:
.cfi_offset rbx, -48
.Ltmp7:
.cfi_offset r12, -40
.Ltmp8:
.cfi_offset r14, -32
.Ltmp9:
.cfi_offset r15, -24
.Ltmp10:
.cfi_offset rbp, -16
xor r14d, r14d
xor edi, edi
call srand
mov r15d, -1
mov r13d, 1 # HAND CODED
# implicit-def: EBX
.align 16, 0x90
.LBB1_1: # %.preheader
# =>This Loop Header: Depth=1
# Child Loop BB1_2 Depth 2
mov ebp, 1000000
.align 16, 0x90
.LBB1_2: # Parent Loop BB1_1 Depth=1
# => This Inner Loop Header: Depth=2
call rand
mov r12d, eax
call rand
xor ecx,ecx #hand coded
cmp r12d, eax
cmovl ecx, r15d #hand coded
cmovg ecx, r13d #hand coded
add ebx, ecx
.LBB1_3:
dec ebp
jne .LBB1_2
# BB#5: # in Loop: Header=BB1_1 Depth=1
inc r14d
cmp r14d, 500
jne .LBB1_1
# BB#6:
mov eax, ebx
pop rbx
pop r12
pop r14
pop r15
pop rbp
ret
.Ltmp11:
.size main, .Ltmp11-main
.cfi_endproc
.ident "Debian clang version 3.5.0-1~exp1 (trunk) (based on LLVM 3.5.0)"
.section ".note.GNU-stack","",#progbits
Question 1: LLVM IR is machine independent. Some machines might not even have a carry flag, or even a zero flag or sign flag. The return value is i1 which suffices to indicate TRUE or FALSE. You can set the comparison condition like 'eq' and then check the result to see if the two operands are equal or not, etc.
Question 2: LLVM IR does not care about optimization initially. The main goal is to generate a Static Single Assignment (SSA) based representation of instructions. Optimization happens in later passes of which some are machine independent and some are machine dependent. Your br2 idea will assume that the machine will support those 3 flags which might be a wrong assumption,
Question 3: I am not sure what you are trying to do here. Can you explain more?
I am trying to write a simple sum function in x86 assembly - to which i am passing 3 and 8 as arguments. However, the code doesn't print the sum. Appreciate any help in spotting the errors. I'm using NASM
section .text
global _start
_sum:
push ebp
mov ebp, esp
push edi
push esi ;prologue ends
mov eax, [ebp+8]
add eax, [ebp+12]
pop esi ;epilogue begins
pop edi
mov esp, ebp
pop ebp
ret 8
_start:
push 8
push 3
call _sum
mov edx, 1
mov ecx, eax
mov ebx, 1 ;stdout
mov eax, 4 ;write
int 0x80
mov ebx, 0
mov eax, 1 ;exit
int 0x80
To me, this looks like Linux assembler. From this page, in the Examples section, subsection int 0x80, it looks like ecx expects the address of the string:
_start:
movl $4, %eax ; use the write syscall
movl $1, %ebx ; write to stdout
movl $msg, %ecx ; use string "Hello World"
movl $12, %edx ; write 12 characters
int $0x80 ; make syscall
So, you'll have to get a spare chunk of memory, convert your result to a string, probably null-terminate that string, and then call the write with the address of the string in ecx.
For an example of how to convert an integer to a string see Printing an Int (or Int to String) You'll have to store each digit in a string instead of printing it, and null-terminate it. Then you can print the string.
Sorry, I have not programmed in assembly in years, so I cannot give you a more detailed answer, but hope that this will be enough to point you in the right direction.
Hi guys I am trying to build the following function
function int Main(){
return 5;
}
this is my assembly code:
.globl Main
Main:
pushl %ebp
movl %esp, %ebp
subl $0, %esp
pushl $5
movl %ebp, %esp
popl %ebp
ret
However this always returns 1 it never returns 5 why?
How about just:
Main:
push byte 5
pop eax
ret
Summarizing what everyone said: your primary error is that the return value should go into EAX and it does not. Prolog and epilog code are not necessary for simple functions like this, but they won't hurt either (as long as they don't unbalance the stack). So the assembly should go:
(prolog)
movl $5, %eax,
(epilog)
ret
Where prolog and epilog are whatever your compiler generates by default.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
assembly function flow
assembly function flow
hello
I am reading a "programming from the ground up"
if you don't know what this book is, you still can help me.
in this book(chapter 4) there are 2 things that I don't understand.
Q. I don't understand
what "movl %ebx, -4(%ebp) #store current result" for.
and what does "current result" means
in marked section in the code below
little upperside, there is
"movl 8(%ebp), %ebx" which means save 8(%ebp) to %ebx
but the reason why I don't understand is
if the programmer want 8(%ebp) to save to -4(%ebp),
why should 8(%ebp) be passed through %ebx?
is "movl 8(%ebp), -4(%ebp)" akward?
or is there any typo in "movl 8(%ebp), %ebx #put first argument in %eax"?
(I think %ebx should be %eax or vice versa)
#PURPOSE: Program to illustrate how functions work
# This program will compute the value of
# 2^3 + 5^2
#
#Everything in the main program is stored in registers,
#so the data section doesn’t have anything.
.section .data
.section .text
.globl _start
_start:
pushl $3 #push second argument
pushl $2 #push first argument
call power #call the function
addl $8, %esp #move the stack pointer back
pushl %eax #save the first answer before
#calling the next function
pushl $2 #push second argument
pushl $5 #push first argument
call power #call the function
addl $8, %esp #move the stack pointer back
popl %ebx #The second answer is already
#in %eax. We saved the
#first answer onto the stack,
#so now we can just pop it
#out into %ebx
addl %eax, %ebx #add them together
#the result is in %ebx
movl $1, %eax #exit (%ebx is returned)
int $0x80
#PURPOSE: This function is used to compute
# the value of a number raised to
# a power.
#
#INPUT: First argument - the base number
# Second argument - the power to
# raise it to
#
#OUTPUT: Will give the result as a return value
#
#NOTES: The power must be 1 or greater
#
#VARIABLES:
# %ebx - holds the base number
# %ecx - holds the power
#
# -4(%ebp) - holds the current result
#
# %eax is used for temporary storage
#
.type power, #function
power:
pushl %ebp #save old base pointer
movl %esp, %ebp #make stack pointer the base pointer
subl $4, %esp #get room for our local storage
##########################################
movl 8(%ebp), %ebx #put first argument in %eax
movl 12(%ebp), %ecx #put second argument in %ecx
movl %ebx, -4(%ebp) #store current result
##########################################
power_loop_start:
cmpl $1, %ecx #if the power is 1, we are done
je end_power
movl -4(%ebp), %eax #move the current result into %eax
imull %ebx, %eax #multiply the current result by
#the base number
movl %eax, -4(%ebp) #store the current result
decl %ecx #decrease the power
jmp power_loop_start #run for the next power
end_power:
movl -4(%ebp), %eax #return value goes in %eax
movl %ebp, %esp #restore the stack pointer
popl %ebp #restore the base pointer
ret
is "movl 8(%ebp), -4(%ebp)" akward
Yes it is. In fact, the processor cannot do it. There are not enough memory fetch/write components to the processor to do both a read and a write in the same command. Due to this, in order to move a value from one memory spot to another, it must first be copied into a register.
In the x86 world, I know it would be possible to push the value from the source, the pop it to the destination. This would effectively copy memory to memory to memory, but this is a special case and is most likely slower than the one you listed.