NASM - The Netwide Assembler
NASM Forum => Using NASM => Topic started by: MrCBofBCinTX on October 24, 2012, 10:19:02 AM
-
I keep seeing other examples ( not NASM ) saying that pushing an extra long is needed.
But I don't see that here or any other examples I see.
What's up with this?
section .note.openbsd.ident
align 2
dd 8
dd 4
dd 1
db 'OpenBSD',0
dd 0
align 2
section .text
global _start ;must be declared for linker (ld)
_syscall:
int 0x80 ;system call
ret
_start: ;tell linker entry point
push dword len ;message length
push dword msg ;message to write
push dword 1 ;file descriptor (stdout)
mov eax,0x4 ;system call number (sys_write)
call _syscall ;call kernel
;the alternate way to call kernel:
;push eax
;call 7:0
add esp,12 ;clean stack (3 arguments * 4)
push dword 0 ;exit code
mov eax,0x1 ;system call number (sys_exit)
call _syscall ;call kernel
;we do not return from sys_exit,
;there's no need to clean stack
section .data
msg db "Hello, world!",0xa ;our dear string
len equ $ - msg ;length of our dear string
This needs an extra long (of any value) pushed.
entropy@theo {~/asm} cat hello.s
.section ".note.openbsd.ident", "a"
.p2align 2
.long 0x8
.long 0x4
.long 0x1
.ascii "OpenBSD\0"
.long 0x
.p2align 2
.section .data
hello:
.ascii "Hello, World!\n\0"
.section .text
.globl _start
_start:
pushl $14 # number of bytes to write
pushl $hello # address of our string
pushl $1 # 1 is stdout
pushl %eax # push the extra long
movl $4, %eax # 4 is write syscall
int $0x80 # call the kernel
addl $12, %esp # clean the stack - add ((# of pushl's)-1)*4 to esp
xor %eax, %eax # set eax to 0
pushl %eax # pushl return (status value)
pushl %eax # pushl extra long
movl $1, %eax # 1 is exit syscall
int $0x80 # call the kernel
Assemble, link and execute.
-
I'm not sure of the exact history but apparently that extra push is needed for all BSDs. In your first example the extra push is accomplished via the call opcode which pushes the eip on the stack. Without using call, as in your second example, you must push a value ( it doesn't seem to matter what value you push ). Thus, from the int 0x80 point of view, the first parameter is always at the same offset on the stack on entry. Also remember if you push the extra value yourself you need to account for that in stack cleanup too. In your 2nd example you really need addl $16, esp instead of addl $12, esp
It may make more sense if you think about how the stack is affected via a call using the C calling convention. This is also one of the differences between Linux and BSD whereby Linux uses registers, rather than the stack, when passing values to the kernel. For x64 kernel calls: the syscall opcode replaces int 0x80 and both use similar registers for parameters: EDI,ESI,EDX,ECX,R8,R9 ( except Linux uses R10 instead of RCX for any syscall having 4 or more parameters ).
Hope that helps.
-
Thanks,
I tried with the extra 16 on esp and with int 80h directly. Works fine.