I'm trying to write a simple compiler. My language can calculate an arithmetic expression using float numbers, save a variable and print a variable. In the first version of my compiler all my calculations only using a push and pop. Then I make calculate with call absolute stack address. I have not allocated memory with sub rsp, but rather I used [rsp-8*x], where x is number of value on the stack, like a push and pop. But the issue is that it does not work with pow function from libc. I can't understand, what I'm doing wrong.
I refactored the code a bit, for your convenience.
My first version in assembly (nasm syntax):
[bits 64]
global _start
extern printf
extern pow
section .data
printf_format db '%lf', 10, 0
section .text
_start:
mov rbp, rsp
sub rsp, 0x20
mov rax, 0x4000000000000000
push rax
mov rax, 0x4000000000000000
push rax
mov rax, 0x4008000000000000
push rax
movsd xmm0, qword [rsp+8]
movsd xmm1, qword [rsp]
call pow
movsd qword [rsp+8], xmm0
add rsp, 8
movsd xmm0, qword [rsp+8]
movsd xmm1, qword [rsp]
call pow
mov rdi, printf_format
mov rax, 1
call printf
mov rax, 60
mov rdi, 0
syscall
My second version:
[bits 64]
global _start
extern printf
extern pow
section .data
printf_format db '%lf', 10, 0
section .text
_start:
mov rbp, rsp
sub rsp, 0x20
mov rax, 0x4000000000000000
mov qword [rsp-8*1], rax
mov rax, 0x4000000000000000
mov qword [rsp-8*2], rax
mov rax, 0x4008000000000000
mov qword [rsp-8*3], rax
movsd xmm0, qword [rsp-8*2]
movsd xmm1, qword [rsp-8*3]
call pow
movsd qword [rsp-8*2], xmm0
movsd xmm0, qword [rsp-8*1]
movsd xmm1, qword [rsp-8*2]
call pow
mov rdi, printf_format
mov rax, 1
call printf
mov rax, 60
mov rdi, 0
syscall
I compile and link this with:
nasm -f elf64 ex.asm
ld -lc -lm -m elf_x86_64 -I/lib/ld-linux-x86-64.so.2 ex.o -o ex
In the last version of my compiler, I wrote the call with [rsp+8*x] and allocated with sub rsp, and the problem was solved.
My question is: Why that change I made solved this problem?
Related
This question already has answers here:
After entering _start, is rsp aligned?
(1 answer)
Should %rsp be aligned to 16-byte boundary before calling a function in NASM?
(1 answer)
Why does the x86-64 / AMD64 System V ABI mandate a 16 byte stack alignment?
(1 answer)
Closed 9 months ago.
I have the following code snippet (https://godbolt.org/z/cE1qE9fvv) which contains a naive & vectorized version of a dot product.
I decided to make the vectorized version compile in standalone asm file as following:
extern exit
section .text
global _start
_start:
mov rax, 8589934593
mov QWORD [rsp-72], rax
mov rax, 17179869187
mov QWORD [rsp-64], rax
mov rax, 25769803781
mov QWORD [rsp-56], rax
mov rax, 34359738375
mov QWORD [rsp-48], rax
mov rax, 85899345930
mov QWORD [rsp-40], rax
mov rax, 171798691870
mov QWORD [rsp-32], rax
mov rax, 257698037810
mov QWORD [rsp-24], rax
mov rax, 343597383750
mov QWORD [rsp-16], rax
movdqa xmm1, [rsp-72]
movdqa xmm0, [rsp-24]
pmulld xmm1, [rsp-40]
pmulld xmm0, [rsp-56]
paddd xmm0, xmm1
movdqa xmm1, xmm0
psrldq xmm1, 8
paddd xmm0, xmm1
movdqa xmm1, xmm0
psrldq xmm1, 4
paddd xmm0, xmm1
movd eax, xmm0
.exit:
call exit
I use the following to build: nasm -f elf64 dot_product.asm && gcc -g -no-pie -nostartfiles -o dot_product dot_product.o
The above code segfault at movdqa xmm0, XMMWORD PTR [rsp-72] which probably means that the data is not 16-bytes aligned. However, the following screenshot seems to indicate the opposite:
Am I misunderstanding something ?
This question already has answers here:
Add a constant value to a xmm register in x86
(2 answers)
How to move a floating-point constant value into an xmm register?
(2 answers)
Closed 1 year ago.
This program reads values from text file and compare or value are greater or not. The problem is that I can't load a constant value as a criteria for ucomisd function. The value in this case are always 0. Can you suggest how to sort out this problem? I searched also other methods how to load the constant value to yasm however it doesn't worked neither.
global st_did_suma
section .text
;-----------------------------------------------------------------------------
; double st_did_suma(double* matrica, uint64_t N)
; rdi rsi
;-----------------------------------------------------------------------------
st_did_suma:
push rbx
push r11
push r8
push rcx
push rdx
push rbp
mov rax, rsi
mul rsi
xorpd xmm0, xmm0
cmp rsi, 0
je .end
cmp rsi, 1
jnz .next
movsd xmm0, qword [rdi]
jmp .end
.next:
add rdi, 8
dec rsi
movsd xmm1, qword [rdi]
mov eax, 100.0 ; XMM2 VALUE ALLWAYS 0
movd xmm2, eax
ucomisd xmm1, xmm2 ; COMPARE FUNCTION
jb .else
mov r10, 1 ; ANSWER
cvtsi2sd xmm0, r10
jnz .next
.else:
subsd xmm1, xmm1
addsd xmm0, xmm1 ; ANSWER
jmp .end
.end:
pop rbp
pop rdx
pop rcx
pop r11
pop r8
pop rbx
ret
I am trying to build a malloc function in assembly. My plan is to use the brk syscall, however in order to do this, I need to be able to know where the end of the current segment is. In c I could use sbrk(0) however this isn't available in assembly. Is there anyway to get the end of the data segment, aside from just putting a label at the bottom.
I am using Ubuntu, nasm, and ld if it helps.
I am assembling and linking with:
nasm -f elf64 mem.s -o mem.o
ld -m elf_x86_64 -o mem mem.o -e _start
mem.asm
global _start
%include "stdasm.s"
section .text
_start:
mov rax, 1
mov rbx, str
call print
mov rax, 0x0123456789ABCDEF
call regPrint
mov rax, end
call regPrint
mov rax, _end
call regPrint
call exit
section .data
str: db 'Hello, world!',0x0A,0
end:
stdasm.s
section .text
exit:
mov rax, 1
mov rbx, 0
int 0x80
print:;rax = fd, rbx = string
push rdx
push rcx
mov rcx, rbx
mov rbx, rax
.loop:
cmp byte [rcx], 0
je .exit
mov rdx, 1
mov rax, 4
int 0x80
inc rcx
jmp .loop
.exit:
pop rcx
pop rdx
ret
regPrint:
push rbx
push rcx
push rdx
xor rcx, rcx
mov rbx, regPrintBuf
.loop:
rol rax, 4
mov dl, al
and rdx, 0x0F
add rdx, hexStr
mov dl, byte [rdx]
mov byte [rbx], dl
inc rcx
inc rbx
cmp rcx, 16
jl .loop
mov rbx, regPrintBuf
mov rax, 1
call print
pop rdx
pop rcx
pop rbx
ret
section .data
hexStr: db '0123456789ABCDEF'
regPrintBuf: db '0000000000000000', 0x0A,0
The linker creates the symbol _end pointing to the end of the data segment at link time. You can use this symbol to find the end of the data segment.
The area allocated by brk is not continuous with the data segment of the executable unless address space layout randomisation is disabled.
To find the current end of this area call brk with an argument of 0. At program start the size is zero so the end address is the same as the start address.
I'm trying to write a library (shared object) in assembly. I'm compiling with nasm and linking with ld. I've got 2 ASM files containing differents symbols. I'm trying to call a symbol contained in the first file from the second one, but ld keep throwing an error : relocation R_X86_64_PC32 against symbol 'strchr' can not be used when making a shared object; recompile with -fPIC.
The first file contains :
BITS 64
section .text
global strchr
strchr:
push rbp
mov rbp, rsp
xor rax, rax
looper:
cmp sil, byte [rdi]
je saveptr
cmp byte [rdi], 0x0
je endloop
inc rdi
jmp looper
saveptr:
mov rax, rdi
endloop:
mov rsp, rbp
pop rbp
ret
The second file contains :
BITS 64
section .text
extern strchr
global strspn
strspn:
push rbp
mov rbp, rsp
xor rax, rax
xor r11, r11
mov rax, rdi
looper:
cmp byte [rsi], 0x0
je endloop
push rax
mov sil, byte [rsi]
call strchr
cmp rax, 0x0
jne increase
inc rsi
mov rax, rdi
jmp looper
increase:
inc r11
inc rax
jmp looper
endloop:
mov rax, r11
mov rsp, rbp
pop rbp
ret
I'm compiling the library through this process:
nasm -f elf64 first_file.asm -o first_file.o
nasm -f elf64 second_file.asm -o second_file.o
ld -shared first_file.o second_file.o -o mylib.so
How can I link the first (compiled) ASM file so that I can call the symbol from the second one ?
I am learning x86_64 NASM assembly on Ubuntu 16.10 on Docker for Mac.
The following program takes two command line arguments, and sum these.
If number of command line arguments is not two, print error message (jump to argcError).
When I exec this program, it jump to argcError section despite passed to two command line arguments.
Why this program jump to argError?
section .data
SYS_WRITE equ 1
STD_IN equ 1
SYS_EXIT equ 60
EXIT_CODE equ 0
NEW_LINE db 0xa
WRONG_ARGC db "Must be two command line arguments", 0xa
section .text
global _start
_start:
pop rcx
cmp rcx, 3
jne argcError
add rsp, 8
pop rsi
call str_to_int
mov r10, rax
pop rsi
call str_to_int
mov r11, rax
add r10, r11
argcError:
mov rax, 1
mov rdi, 1
mov rsi, WRONG_ARGC
mov rdx, 35
syscall
jmp exit
str_to_int:
xor rax, rax
mov rcx, 10
next:
cmp [rsi], byte 0
je return_str
mov bl, [rsi]
sub bl, 48
mul rcx ; rax = rax * rcx
add rax, rbx
inc rsi
jmp next
return_str:
ret
int_to_str:
mov rdx, 0
mov rbx, 10
div rbx
add rdx, 48
add rdx, 0x0
push rdx
inc r12
cmp rax, 0x0
jne int_to_str
jmp print
print:
; calculate byte length of number string
mov rax, 1
mul r12
mov r12, 8
mul r12
mov rdx, rax
; print sum
mov rax, SYS_WRITE
mov rdi, STD_IN
mov rsi, rsp
syscall
jmp printNewline
printNewline:
mov rax, SYS_WRITE
mov rdi, STD_IN
mov rsi, NEW_LINE
mov rdx, 1
syscall
jmp exit
exit:
mov rax, SYS_EXIT
mov rdi, EXIT_CODE
syscall
There probably other errors in your code as pointed out by Micheal Petch, but the way you've initialized RSI is incorrect. Yes, ESP does point to the number of arguments passed, but popping it off the stack and then adding 8 to ESP again is functionally equivalent too.
mov rcx, [rsp]
Then by popping into RSI it only becomes a copy of RCX. If you want to do that it should look like this
pop rcx
.......
add rsp, 24 ; Now RSP is pointing to proper place in array of pointers
pop rsi
add rsp, 16 ; Now point to pointer to second argument
pop rsi
An alternative would be this next example only because my personal preference is not to use stack pointer for other than that which it was intended.
mov rsi, rsp
lodsq ; Read # of arguments passed by OS
add rsi, 8 ; bounce over application name
cmp al, 3
jnz argError
push rsi
lodsq
mov rsi, rax ; RSI points to first agument
call Convert
pop rsi
lodsq
mov rsi, rax
call Convert