NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: MediocreVeg1 on January 08, 2021, 06:32:57 AM
-
I've been using macros for most of this time, but I'm pretty sure using them too much could cause certain problems, and I see people using mostly procedures anyway, so i decided to give procedures a go.
Here is the procedure:
foo:
pop dword [eax]
mov ecx, eax
mov edx, 1
mov eax, 4
mov ebx, 1
int 80h
add esp, 4
ret
and here is how i envoke it:
push num
call foo
Here, I'm trying to pass num as a parameter, but when run this program, I get a segfault. It might be because of cleaning the stack. Any help would be greatly appreciated.
-
Update: I realised I was being stupid with the [] so I changed my function to:
foo:
mov eax, 4
mov ebx, 1
pop ecx
mov edx, 1
int 80h
ret
This prints something (comes out as an unknown character) and then still gives a segfault. I'm not even sure why its printing an unknown character since num is 48, so it should print 0.
-
Update: I realised I was being stupid with the [] so I changed my function to:
foo:
mov eax, 4
mov ebx, 1
pop ecx
mov edx, 1
int 80h
ret
This prints something (comes out as an unknown character) and then still gives a segfault. I'm not even sure why its printing an unknown character since num is 48, so it should print 0.
For i386 syscalls ECX holds the pointer to a buffer, not the "character". If you 'push' the number to the stack you could do (assuming SS=DS):
f:
mov eax,4
mov ebx,1
mov edx,ebx
lea ecx,[esp+4] ; ECX = address of 'num' in the stack.
int 0x80
ret
And call f() as:
push num
call f
add esp,4 ; clear the stack.
-
Sorry for getting this so late, i think i get it now though. Thanks for the help.
[EDIT] Wait, I'm still getting a segfault with this code. Ugh.
I know the stack kindof changes with 32 and 64 bit. Right now, I've put BITS 32 but i compiled it as elf64 and didnt put i386, maybe that's the issue, but I doubt it.
-
[SORT OF UPDATE] About the segfault, I just realised I was being stupid with an ld typo. After that, the segfault went away
BUT
Now it prints... nothing. The program opens and just closes. Is there any reason why this could be?
-
Sorry... my bad..
Pushing a number on stack won't help. A single decimal digit is a char which code is between 0x30 and 0x39
You can push a char...
push byte '3'
call f
add esp,4
...
-
Ok, ill try this out
-
Ah man, wait, I'm still getting nothing even with push byte '3'. And I have a few extra questions too:
1. I'm pretty sure NASM can't really differentiate between numbers and characters (like i mean that add eax, '0' is identical to add eax, 48), and i pushed 48 (0 in ascii), so how would that and '0' be different?
2. I read that you can't push bytes into the stack, only words and doublewords. So how does this new line work, exactly?
-
Ah man, wait, I'm still getting nothing even with push byte '3'.
Then you are doing something wrong. For x86-64, try this (change the registers, the syscall instruction to int 0x80, the EAX to corresponding syscalls and the offset to +4, instead of +8, for i386 code):
; test.asm
;
; $ nasm -felf64 -o test.o test.asm
; $ ld -s -o test test.o
;
bits 64
default rel
section .text
global _start
_start:
push byte '3'
call f
add rsp,8 ; Get rid of pushed data.
mov eax,60
xor edi,edi
syscall
;---------------
align 4
f:
mov eax,1 ; SYS_WRITE.
mov edi,eax ; STDOUT_FILENO.
mov edx,eax ; 1 char.
lea rsi,[rsp+8] ; Points to data pushed on stack.
; The stack:
;
; +-----------------------------------------+
; RSP+8 -> | 0x33 0x00 0x00 0x00 0x00 0x00 0x00 0x00 |
; +-----------------------------------------+
; RSP-> | return address |
; +-----------------------------------------+
syscall
ret
And I have a few extra questions too:
1. I'm pretty sure NASM can't really differentiate between numbers and characters (like i mean that add eax, '0' is identical to add eax, 48), and i pushed 48 (0 in ascii), so how would that and '0' be different?
'0' is 0x30, and 0 is 0...
2. I read that you can't push bytes into the stack, only words and doublewords. So how does this new line work, exactly?
I'm not pushing one single byte... the 'byte' there is to use the shorter version of push. This will zero extend the 'byte' to a DWORD (i386) or QWORD (x86-64).
-
Nitpick: '0' is 0x30 - 48 decimal. 0x48 would be 'H'.
In 64 bit code. push byte '0' goes on rsp... [esp + x] is not the same place. I suspect that this is a good example of why using 32 bit syscalls in 64 bit code can be a problem.
Best,
Frank
-
Ok, the new code works. Thanks a lot (and I'm sorry if i came off as annoying here). There are some questions I still have, like how your printing syscall is different from what I've generally seen and how you seem to be using edi as opposed to ebx, but I think I might have stretched this thread out too far and my original question is answered, so I'll try to figure out the rest myself. Once again, thanks a bunch :)
-
Linux x86-64 syscalls (https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64)
-
I also found the syscalls here https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md , but thanks for the link
-
There are many differences between 64-bit and 32-bit programs in assembly. For example the calling conventions could also be different... So if you were calling a function and you thought arguments needed to all be on the stack, they may need to be in registers and so on... You need to be aware of these differences.
-
Ok. I also know that there are specific registers where arguments are passed now like rdi too, and rax is generally the return / error code register. The stack is proving to be a little problematic since I don't think I can push a string larger than 8 characters, so I might just use registers for params.