Compile assembly (NASM with int 80h system calls) in windows - windows

I am learning to code assembly (NASM). But i have problem, i am coding online but i want to convert this code below to exe and run it. (By clicking double click on it, not in cmd). And i dont have a clue how to do it. i know i must use a nasm from https:://www.nasm.us and a linker. For the linker i want to use ld from mingw. but i dont know how to do it. i didnt find any thing on the internet
section .data
msg: db "Eneter your name : ", 10
msg_l: equ $-msg
hello: db "Hello, "
hello_l: equ $-hello
section .bss
name: resb 255
section .text
global _start:
_start:
mov eax, 4
mov ebx, 1
mov ecx, msg
mov edx, msg_l
int 80h
mov eax, 3
mov ebx, 0
mov ecx, name
mov edx, 255
int 80h
mov eax, 4
mov ebx, 1
mov ecx, hello
mov edx, hello_l
int 80h
mov eax, 4
mov ebx, 1
mov ecx, name
mov edx, 255
int 80h
mov eax, 1
mov ebx, 0
int 80h

The best way to work with linux in windows is to use wsl2. The windows subsystem will allow you to use real linux system calls. There is a learning curve but its worth it.
Follow a guide on how to install ws2.
Go to the windows store and download one of the few linux terminals. I use ubuntu.
Install gcc in the terminal so that you will have a gnu compiler, gnu assembler, and the gnu linker(ld).
Install nasm in the terminal. Not the windows app version.
After everything is set up, you can get a nice workflow going.
you would open the terminal.
change directories which will get you into the c drive: cd /mnt/c
create a folder in the c drive where you want to do your work
change directories to that folder: cd foldername
create a nasm asm file and put some code into it.
then you can use nasm to assemble, ld to link, execute
When you assemble with nasm you can now use elf:
nasm -f elf32 main.asm
ld -m elf_i386 main.o -o main
./main
or:
nasm -f elf64 main.asm
ld main.o -o main
./main

Related

Successive sys_write syscalls not working as expected, NASM bug on OS X?

I'm trying to learn MacOS assembly using NASM and I can't get a trivial program to work. I'm trying a variation of the "Hello, World" where the two words are independently called by a macro. My source code looks like this:
%macro printString 2
mov rax, 0x2000004 ; write
mov rdi, 1 ; stdout
mov rsi, %1
mov rdx, %2
syscall
%endmacro
global start
section .text
start:
printString str1,str1.len
printString str2,str2.len
mov rax, 0x2000001 ; exit
mov rdi, 0
syscall
section .data
str1: db "Hello,",10,
.len: equ $ - str1
str2: db "world",10
.len: equ $ - str2
The expected result should be:
$./hw
Hello,
World
$
Instead I get:
$./hw
Hello,
$
What am I missing? How do I fix it?
EDIT: I am compiling & running with the following commands:
/usr/local/bin/nasm -f macho64 hw.asm
ld -macosx_version_min 10.7.0 -lSystem -o hw hw.o
./hw
NASM 2.11.08 and 2.13.02+ have bugs with macho64 output. What you are observing seems to be something I saw specifically with 2.13.02+ recently when using absolute references. The final linked program has incorrect fixups applied so the reference to str2 is incorrect. The incorrect fixup causes us to print out memory that isn't str2.
NASM has a bug report about this issue in their system. I have added a specific example of this failure based on the code in the question. Hopefully the NASM developers will be able to reproduce the failure and create a fix.
Update: As of June 2018 my view is that there are enough recurring bugs and regressions in NASM that I do not recommend NASM at this point in time for Macho-64 development.
Another recommendation I have for Macho-64 development is to use RIP relative addressing rather than absolute. RIP relative addressing is the default for 64-bit programs on later versions of MacOS.
In NASM you can use the default rel directive in your file to change the default from absolute to RIP relative addresses. For this to work you will have to change from using mov register, variable to lea register, [variable] when trying to move the address of a variable to a register. Your revised code could look like:
default rel
%macro printString 2
mov rax, 0x2000004 ; write
mov rdi, 1 ; stdout
lea rsi, [%1]
mov rdx, %2
syscall
%endmacro
global start
section .text
start:
printString str1,str1.len
printString str2,str2.len
mov rax, 0x2000001 ; exit
mov rdi, 0
syscall
section .data
str1: db "Hello,",10
.len: equ $ - str1
str2: db "world",10
.len: equ $ - str2

Incorrect string address in generated executable [duplicate]

I'm trying to learn MacOS assembly using NASM and I can't get a trivial program to work. I'm trying a variation of the "Hello, World" where the two words are independently called by a macro. My source code looks like this:
%macro printString 2
mov rax, 0x2000004 ; write
mov rdi, 1 ; stdout
mov rsi, %1
mov rdx, %2
syscall
%endmacro
global start
section .text
start:
printString str1,str1.len
printString str2,str2.len
mov rax, 0x2000001 ; exit
mov rdi, 0
syscall
section .data
str1: db "Hello,",10,
.len: equ $ - str1
str2: db "world",10
.len: equ $ - str2
The expected result should be:
$./hw
Hello,
World
$
Instead I get:
$./hw
Hello,
$
What am I missing? How do I fix it?
EDIT: I am compiling & running with the following commands:
/usr/local/bin/nasm -f macho64 hw.asm
ld -macosx_version_min 10.7.0 -lSystem -o hw hw.o
./hw
NASM 2.11.08 and 2.13.02+ have bugs with macho64 output. What you are observing seems to be something I saw specifically with 2.13.02+ recently when using absolute references. The final linked program has incorrect fixups applied so the reference to str2 is incorrect. The incorrect fixup causes us to print out memory that isn't str2.
NASM has a bug report about this issue in their system. I have added a specific example of this failure based on the code in the question. Hopefully the NASM developers will be able to reproduce the failure and create a fix.
Update: As of June 2018 my view is that there are enough recurring bugs and regressions in NASM that I do not recommend NASM at this point in time for Macho-64 development.
Another recommendation I have for Macho-64 development is to use RIP relative addressing rather than absolute. RIP relative addressing is the default for 64-bit programs on later versions of MacOS.
In NASM you can use the default rel directive in your file to change the default from absolute to RIP relative addresses. For this to work you will have to change from using mov register, variable to lea register, [variable] when trying to move the address of a variable to a register. Your revised code could look like:
default rel
%macro printString 2
mov rax, 0x2000004 ; write
mov rdi, 1 ; stdout
lea rsi, [%1]
mov rdx, %2
syscall
%endmacro
global start
section .text
start:
printString str1,str1.len
printString str2,str2.len
mov rax, 0x2000001 ; exit
mov rdi, 0
syscall
section .data
str1: db "Hello,",10
.len: equ $ - str1
str2: db "world",10
.len: equ $ - str2

Use NASM to compile 32-bit assembly for x86_64 environment

I'm reading a book where all the assembly code examples are written for 32-bit Linux environment, and I'm using a 64-bit Mac. I was able to compile the following program with NASM after changing _start to start. However, when I run the executable it doesn't print hello world as I would expect it to. Is there an option to pass to NASM to compile this in a way that will run on a 64-bit Mac?
I tried:
nasm -f macho32 helloworld.asm
and
nasm -f macho helloworld.asm
followed by:
ld helloworld.o -o helloworld
My code is:
section .data ; data segment
msg db "Hello, world!", 0x0a ; the string and newline char
section .text ; text segment
global start ; Default entry point for ELF linking
start:
; SYSCALL: write(1, msg, 14)
mov eax, 4 ; put 4 into eax, since write is syscall #4
mov ebx, 1 ; put 1 into ebx, since stdout is 1
mov ecx, msg ; put the address of the string into ecx
mov edx, 14 ; put 14 into edx, since our string is 14 bytes
int 0x80 ; Call the kernel to make the system call happen
; SYSCALL: exit(0)
mov eax, 1 ; put 1 into eax, since exit is syscall #1
mov ebx, 0 ; exit with success
int 0x80 ; do the syscall
It's simply not going to work like that. Get a VM and install 32 bit linux in the VM. The problem is not running x86_32 code on x64. The problem is trying the Linux syscall gate on MAC. There's no reason to believe that would work.

Mac OS X: YASM: error: macho: sorry, cannot apply 32 bit absolute relocations in 64 mode [duplicate]

This question already has an answer here:
Mach-O 64-bit format does not support 32-bit absolute addresses. NASM Accessing Array
(1 answer)
Closed 4 years ago.
NASM compiles just fine, but when i use YASM I'm getting the following error:
hello.asm:12: error: macho: sorry, cannot apply 32 bit absolute
relocations in 64 bit mode, consider "[_symbol wrt rip]" for mem
access, "qword" and "dq _foo" for pointers.
Makefile
test: hello
./hello
hello:
yasm -f macho64 hello.asm
ld -o hello hello.o
clean:
rm *.o *.core hello
system.inc
%define stdin 0
%define stdout 1
%define stderr 2
%define SYS_nosys 0
%define SYS_exit 1
%define SYS_fork 2
%define SYS_read 3
%define SYS_write 4
section .text
align 4
access.the.osx.kernel:
syscall
ret
%macro system 1
mov rax, %1
call access.the.osx.kernel
%endmacro
%macro sys.exit 0
system SYS_exit
%endmacro
%macro sys.write 0
system SYS_write
%endmacro
hello.asm
%include 'system.inc'
section .data
hello db 'Hello, World!', 0Ah
hbytes equ $-hello
section .text
global start
start:
mov rax, 0x2000004
mov rdi, stdout
mov rsi, hello
mov rdx, hbytes
syscall
;sys.write
xor rdi, rdi
mov rax, 0x2000001
syscall
;sys.exit
Anyone know what's going on? And if you could explain why NASM works, but YASM doesn't that would be a bonus.
I got it working. In yasm you have to explicitly tell it that the address is 64-bit like so:
mov rsi, qword hello
The documentation talks about the situation here: https://github.com/yasm/yasm/wiki/AMD64

Hello world using nasm in windows assembly

I'm using nasm to compile the following assembly. However the code crashes in the console under Windows.
C:\>nasm -f win32 test.asm -o test.o
C:\>ld test.o -o test.exe
section .data
msg db 'Hello world!', 0AH
len equ $-msg
section .text
global _WinMain#16
_WinMain#16:
mov edx, len
mov ecx, msg
mov ebx, 1
mov eax, 4
int 80h
mov ebx, 0
mov eax, 1
int 80h
According to this post. The main function is not available under Windows and must be replaced by WinMain.
So if your entry point is _start or main, it should be changed to _WinMain#16 and change the ret at the end of the procedure to ret 16:
My working example:
section .text
global _WinMain#16
_WinMain#16:
mov eax, 0
ret 16
The biggest problem is that you are trying to use Linux interupts on windows!
int 80 will NOT work on windows.
We are using Assembly, so your entry point can be ANY label you want. The standard entry point that ld looks for is _start, if you want to use another label, you need to tell ld with the -e option
So if you want your start label to be main, then you need
global main
ld -e main test.o -o test.exe
If you are going to use NASM on Windows, I will recommend using GoLink as your linker.
Here is a simple windows console app:
STD_OUTPUT_HANDLE equ -11
NULL equ 0
global GobleyGook
extern ExitProcess, GetStdHandle, WriteConsoleA
section .data
msg db "Hello World!", 13, 10, 0
msg.len equ $ - msg
section .bss
dummy resd 1
section .text
GobleyGook:
push STD_OUTPUT_HANDLE
call GetStdHandle
push NULL
push dummy
push msg.len
push msg
push eax
call WriteConsoleA
push NULL
call ExitProcess
makefile:
hello: hello.obj
GoLink.exe /console /entry GobleyGook hello.obj kernel32.dll
hello.obj: hello.asm
nasm -f win32 hello.asm -o hello.obj
Although, this same program probably will run in WINE on Linux like a charm. :)
WINE doesn't prevent using Linux system calls from inside Windows PE binaries; the machine instructions run natively and WINE only provides DLL functions.

Resources