linux assembly: how to call syscall? - linux

I want to call a syscall in assembly. The problem is I can't mov ecx,rsp. rsp is 64-bit register, ecx is a 32-bit register. I want to pass the buffer addr as a parameter of this syscall. What can I do? Thanks.
section .data
s0: db "Largest basic function number supported:%s\n",0
s0len: equ $-s0
section .text
global main
extern write
main:
sub rsp, 16
xor eax, eax
cpuid
mov [rsp], ebx
mov [rsp+4], edx
mov [rsp+8], ecx
mov [rsp+12], word 0x0
mov eax, 4
mov ebx, 1
mov ecx, rsp
mov edx, 4
int 80h
mov eax, 4
mov ebx, 1
mov ecx, s0
mov edx, s0len
int 80h
mov eax, 1
int 80h

To make a system call in 64-bit Linux, place the system call number in rax, and its arguments, in order, in rdi, rsi, rdx, r10, r8, and r9, then invoke syscall.
Note that 64-bit call numbers are different from 32-bit call numbers.
Here is an example in GAS syntax. NASM syntax for putting an address in a register is lea rsi, [rel message] using a RIP-relative LEA.
.global _start
.text
_start:
# write(1, message, 13)
mov $1, %rax # system call 1 is write
mov $1, %rdi # file handle 1 is stdout
lea message(%rip), %rsi # address of string to output
mov $13, %rdx # number of bytes
syscall
# exit(0)
mov $60, %rax # system call 60 is exit
xor %rdi, %rdi # return code 0
syscall
.section .rodata # read-only data section
message:
.ascii "Hello, World\n"
See also What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?

Related

Assembly NASM - AND Mask

When I run this program it says:
jdoodle.asm:9: error: invalid combination of opcode and operands
The problem is the AND al, ah. The rest of the code should be correct, I just need to know how to solve this problem because as it seems I can't do an AND between 2 registers.
section .text
global _start
_start:
call _input
mov al, input
mov ah, maschera
and al, ah
mov input, al
call _output
jmp _exit
_input:
mov eax, 3
mov ebx, 0
mov ecx, input
mov edx, 1
int 80h
ret
_output:
mov eax, 4
mov ebx, 1
mov ecx, input
mov edx, 1
int 80h
ret
_exit:
mov eax, 1
int 80h
section .data
maschera: db 11111111b
segment .bss
input resb 1
MASM/TASM/JWASM syntax is different from NASM. If you want to load/store data at an address you need to explicitly use square brackets. If you want to use the MOV instruction to place the address of a label in a variable you do not use square brackets. Square brackets are like a de-reference operator.
In 32-bit code you will want to ensure addresses are loaded into 32-bit registers. Any address above 255 won't fit in an 8 byte register, any address above 65535 won't fit in a 16-bit register.
The code you were probably looking for is:
section .text
global _start
_start:
call _input
mov al, [input]
mov ah, [maschera]
and al, ah
mov [input], al
call _output
jmp _exit
_input:
mov eax, 3
mov ebx, 0
mov ecx, input
mov edx, 1
int 80h
ret
_output:
mov eax, 4
mov ebx, 1
mov ecx, input
mov edx, 1
int 80h
ret
_exit:
mov eax, 1
int 80h
section .data
maschera: db 11111111b
segment .bss
input resb 1

Get end of data segment in assembly in Linux

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.

Printing binary string in assembly

I'm writing a program to print binary string of a hardcoded word. Here is how it looks like currently:
main.asm
section .text
global _start
extern _print_binary_content
_start:
push word [word_to_print] ; pushing word. Can we push just one byte?
call _print_binary_content
mov rax, 60
mov rdi, 0
syscall
section .data
word_to_print: dw 0xAB0F
printer.asm
SYS_BRK_NUM equ 0x0C
BITS_IN_WORD equ 0x10
SYS_WRITE_NUM equ 0x01
STD_OUT_FD equ 0x01
FIRST_BIT_BIT_MASK equ 0x01
ASCII_NUMBER_OFFSET equ 0x30
section .text
global _print_binary_content
_print_binary_content:
pop rbp
xor ecx, ecx ;zeroing rcx
xor ebx, ebx ;zeroing rbx
pop bx ;the word to print the binary content of
;sys_brk for current location
mov rax, SYS_BRK_NUM
mov rdi, 0
syscall
;end sys_brk
mov r12, rax ;save the current brake location
;sys_brk for memory allocation 16 bytes
lea rdi, [rax + BITS_IN_WORD]
mov rax, SYS_BRK_NUM
syscall
;end sys_brk
xor ecx, ecx
mov cl, byte BITS_IN_WORD - 1; used as a counter in the loop below
loop:
mov dx, bx
and dx, FIRST_BIT_BIT_MASK
add dx, ASCII_NUMBER_OFFSET
mov [r12 + rcx], dl
shr bx, 0x01
dec cl
cmp cl, 0
jge loop
mov rsi, r12
mov rax, SYS_WRITE_NUM
mov rdi, STD_OUT_FD
mov rdx, BITS_IN_WORD
syscall
push rbp ; pushing return address back
ret
If I compile link and run this program it works. But the question is about performance and maybe conventions of writing assembly programs. In the file printer.asm I cleaned ecx twice which looks kind of not optimal. Maybe some registers were used not by their purpose (I used intel-manual).
Can you please help me to improve this very simple program?

open syscall failes to create a file without a reason

section .text
global _start ;must be declared for linker (ld)
_start:
mov eax,5
mov ebx,plname
mov ecx,0x202
mov edx,0700o
int 0x80
mov eax,4
mov ecx,plaintext
mov edx,256
int 0x80
xor eax,eax
inc eax
xor ebx,ebx
int 0x80
section .data
key db '123456passwordqwerty',0x0
keylen equ $ - key ;length of our dear string
plname db 'plname.bin',0x0
plaintext times 256 db 1
first part planned to create a file specified in plname, first time I'd tryed create it into /tmp/plname.bin and after fail, try to create at least into excuting directory.I've also tried create syscall and got the same results.
programm fails on open syscall, after excuting int 0x80 instruction, eax contains -2, programm ends normally, but doesn't create file.
here i got flags and mods
https://sourceware.org/gdb/onlinedocs/gdb/mode_005ft-Values.html#mode_005ft-Values
here is gdb output
Dump of assembler code for function _start:
0x08048080 <+0>: mov $0x8,%eax
0x08048085 <+5>: mov $0x80490c9,%ebx
0x0804808a <+10>: mov $0x700,%ecx
0x0804808f <+15>: int $0x80
0x08048091 <+17>: mov $0x4,%eax
0x08048096 <+22>: mov $0x80490e3,%ecx
0x0804809b <+27>: mov $0x100,%edx
0x080480a0 <+32>: int $0x80
0x080480a2 <+34>: xor %eax,%eax
0x080480a4 <+36>: inc %eax
0x080480a5 <+37>: xor %ebx,%ebx
0x080480a7 <+39>: int $0x80
End of assembler dump.
Breakpoint 1, 0x0804808f in _start ()
(gdb) i r eax
eax 0x5 5
(gdb) stepi
0x08048094 in _start ()
(gdb) i r eax
eax 0x5 5
(gdb) i r eax ebx ecx edx esi edi
eax 0x5 5
ebx 0x80490d1 134516945
ecx 0x202 514
edx 0x1c0 448
esi 0x0 0
edi 0x0 0
(gdb) stepi
0x08048096 in _start ()
(gdb) i r eax ebx ecx edx esi edi
eax 0xfffffffe -2
ebx 0x80490d1 134516945
ecx 0x202 514
edx 0x1c0 448
esi 0x0 0
edi 0x0 0
You used the wrong reference manual. What you linked to is the flags used in the gdb protocol, not the ones used by system calls.
O_CREAT is actually 0100 octal, so you should do mov ecx,0102o.
Also note you have forgotten to move the returned file descriptor from eax to ebx for the sys_write.
Working code:
section .text
global _start ;must be declared for linker (ld)
_start:
mov eax,5
mov ebx,plname
mov ecx,0102o
mov edx,0700o
int 0x80
mov ebx, eax
mov eax,4
mov ecx,plaintext
mov edx,256
int 0x80
xor eax,eax
inc eax
xor ebx,ebx
int 0x80
section .data
key db '123456passwordqwerty',0x0
keylen equ $ - key ;length of our dear string
plname db 'plname.bin',0x0
plaintext times 256 db 1

execvp usage on nasm

I'm learning NASM now, linux system calls probably. I'm trying to copy a process and call linux utility, but have same troubles with execvp, I don't know how to pass arguments into it. How I can do this right?
SECTION .data
cmd_cat: db '/bin/cat', 0
arg_cat: db 'log.txt', 0
cat: dd cmd_cat, arg_cat, 0
fd1: dw 0, 0
pipe_error_message: db 'pipe error occured', 0xa
pipe_error_message_length: equ $ - pipe_error_message
fork_error_message: db 'fork error occured', 0xa
fork_error_message_length: equ $ - fork_error_message
SECTION .text
GLOBAL _start:
_start:
;call pipe(fd1)
;42 - pipe system call number
mov eax, 42
mov ebx, fd1
;call kernel to execute
int 080h
cmp eax, 0
jne pipe_error
;call pipe(fd2)
mov eax, 42
mov ebx, fd1
int 080h
cmp eax, 0
jne pipe_error
;fork()
mov eax, 2
int 080h
cmp eax, -1
je fork_error
jnz child_cat
call exit
;displays error message and finishes the programm when something is wrong with pipe
pipe_error:
mov edx, pipe_error_message_length
mov ecx, pipe_error_message
call sys_write
call exit
;displays error message and finishes the programm when something is wrong with fork
fork_error:
mov edx, fork_error_message_length
mov ecx, fork_error_message
call sys_write
call exit
;sys_write(unsigned int fd, const char __user *buf, size_t count);
sys_write:
mov ebx, 1
mov eax, 4
int 080h
;exit(0)
exit:
mov eax,1
mov ebx,0
int 080h
child_cat:
mov ebx, [fd1]
mov eax, 6
int 080h
;dup2(fds[1],1)
mov ecx, 1
mov ebx, [fds + 4]
mov eax, 63
int 080h
mov eax, 11
mov ebx, cmd_cat
mov ecx, cat
int 080h
The following code works for me in the gas assembler. I have explained what it does, so hopefully someone else can provide the nasm translation.
.text
.global _start
_start:
movl $0xb, %eax # system call 0xb (execve) goes in eax
movl $arg0, %ebx # put the _address_ of the command string
# in ebx (we are providing a pointer)
movl $ptrarray, %ecx # put the _address_ of the array of pointers
# to arguments in ecx (again, a pointer)
movl $0, %edx # put a literal zero in edx (we don't have
# environment variables to pass, so we give
# a null pointer)
int $0x80 # run the system call
.data
ptrarray: # This is the array of pointers to command line
# arguments
.long arg0, arg1, 0 # The first element is a _pointer_ to the command
# The second element is a _pointer_ to an argument
# The third is a null pointer to indicate no more
arg0: # This is the command string
.asciz "/bin/cat"
arg1: # This is the argument string
.asciz "file.txt"

Resources