x86 assembly create Win32 executable NASM - winapi

I want to create a valid Win32 executable, that can be run as standalone application.
For example, this simple program:
bits 32
mov eax,1
ret
I compiled it using NASM with
nasm test.asm -o test.exe
Then I ran that program.
It started NTVDM and it told me "The NTVDM CPU encountered illegal instruction" and some technical details, probably dump, and registers.
So, I want to create a standalone Win32 application in assembly language. I don't want to create COM file, like in DOS.

[section] .text
global _start
_start:
mov eax, 1
ret
can be assembled like this:
nasm -fwin32 file.asm (this should give you file.obj)
and
link /subsystem:windows /entry:start file.obj
(or)
ld -e _start file.obj
whatever linker you choose should give you your .exe

At least Windows XP refuses to load an application that does not use any DLL files. I didn't test with Windows 7 up to now!
The reason is that there are no official interfaces but the DLLs that come with Windows and that a program that has neither inputs nor outputs makes no sense.

Related

.section .text directive on Linux vs. Mac? What information to retrieve on my computer that completely characterizes the assembly syntax?

I would like to start learning assembler. The first question I ask myself is this : when I sit in front of a computer, how to find out which assembly syntax I have to use?
I read many terms on internet as "ABI", "computer architecture", "processor", "compiler" but ultimately I didn't understand what exactly determines the syntax of the assembly language I have to use.
For instance I have a Mac M1 and I installed a Linux virtual machine. I checked my architecture which is AArch64 so I wrote a very simple assembly program :
.global _start
.section .text
_start:
mov x8, #0x5d
mov x0, #0x41
.section .data
For example, this works (compiled with gcc) on my Linux virtual machine but not on the mac directly (also compiled with gcc) because apparently I have to replace .section .data by .data or .section .text by .text. So here I have the same AArch64 architecture and the same compiler, yet the assembly syntax is different... weird.
In short, I would like to know what exact information do I have to look for on a computer (ABI? Architecture? Something else?) in order to know for sure which assembly language syntax to use.
In this case, MacOS uses different section names than other platforms (like ELF on Linux, or COFF/PE on Windows)
.text is an alias for .section __TEXT,__text,regular,pure_instructions when targeting MachO64, unlike .section .text when targeting an ELF object file. At least that's what I see in the asm output from clang -target arm64-macos -S hello.c on my x86-64 Linux desktop for a simple program.
AFAIK, only Clang can target Mach-O 64-bit object files; not sure if GNU Binutils ever got that support. gcc on a Mac is normally actually Apple's version of clang (with some differences from mainline clang like I have on my Linux desktop). Running it doesn't involve the GNU assembler. as on a Mac is also clang; it's a compiler and an assembler.
In general - target OS (or object-file format) and assembler matter, not just CPU architecture. Since x86 was mentioned in comments, that's a good example of an ISA where many different asm source syntaxes exist, and also different OSes with incompatible ABIs and object file formats.
Different x86 assemblers use different syntax for the same machine code. For example, AT&T movl $1234, (%rdi) is the same instruction as NASM mov dword [rdi], 1234. Or GAS .intel_syntax noprefix mov dword ptr [rdi], 1234 (also MASM).
So no, the ISA doesn't uniquely determine the asm text syntax for instructions. Only the machine code. It does narrow down the asm choices to a handful.
Quite a few ISAs only have one syntax for instructions themselves, although 32-bit ARM has some syntax variations, like whether ldreqb or ldrbeq is right. (Predicate as infix before a load-size suffix, or as a suffix). And there's Keil's ARMASM vs. GNU Assembler syntax.

Compiling error whilst using command from NASM and mingw

I want to play a bit with assembly. To get started I've created a little asm script and tried to compile it. In the first step everything went great:
nasm -felf64 hello.asm
But when I tried to use
ld -o hello.o hello
from MinGW an error occured:
hello.o: file not recognized: File format not recognized
What can I do to fix this problem? I've tried it with gcc as well but then the same error plus one other error occurs.
MinGW creates binaries targeting Windows. Windows does not support ELF binaries (or does it? with Windows subsystem for Linux?). Anyway, ld in MinGW will expect that you provide binaries in win64 format not elf64.
nasm -fwin64 hello.asm will most likely work.
No it won't work because I just saw your code, and you are using Linux syscalls under Windows.
Write,
mov rcx, 69
call ExitProcess
instead of,
mov rax, SYS_EXIT
mov rdi, 69
syscall
Leave a comment if it doesn't work.

File format not recognized when trying build an exe from obj in windows

I was trying to build an exe from asm file. The asm file looks like this:
global main
extern puts
section .data
msg:
db "Hello, world!",10,0
section .text
main:
sub rsp, 28h
mov rcx, msg
call puts
add rsp, 28h
ret
Then I assembled it using NASM and tried to link it using GCC. But it is showing this error.
> nasm -fwin64 asmtest.asm
> gcc asmtest.obj
asmtest.obj: file not recognized: File format not recognized
collect2.exe: error: ld returned 1 exit status
I am unable to figure out what is going on. My NASM version 2.14.02 and GCC version 8.1.0. I have followed this tutorial (at the bottom). I am doing this on my Windows 10 64-bit machine.
I have also seen this question, but it didn't help me.
You have installed mingw for 32 bit binaries. You need to install a version of mingw configured to make 64 bit binaries to compile and/or link 64 bit binaries.

Is it true that .exe can't run without .bss section in 64bit windows?

I came across this problem when I noticed some of my old programs failed to run under modern Windows.
Here is a miniature example, built via mingw64
.text
.global start
start:
subq $0x48,%rsp
xorl %ecx,%ecx
call *__imp_ExitProcess(%rip)
addq $0x48,%rsp
ret
gcc a.s -nostdlib -nostartfiles -lkernel32 -Wl,-e,start,-s
A message box says the exe is not valid Win32 program when I open it. However the program runs successfully when I add .lcomm a,1 or
.bss
.int 0
to the source file, both effectively inserting .bss section into the exe file. Adding .data section does not solve the problem.
Is this an inherent restriction of Windows or a bug inside ld?
EDIT:
Ok. I've found many exe files without .bss or any section with uninitialized data but run well nevertheless. But this does not fully answer my question. Why my program with only .data , .text and .idata unable to run?
EDIT V2:
I think I have found the cause. The value of OptionalHeader.SizeOfImage is incorrect. Changing it to correct value solves the problem. So this is most likely a bug inside ld.

Error while linking asm code

I wrote a simple program in assembly language which will simply display a message box in windows 7 32 bit
.386
.model flat, stdcall
option casemap :none
extrn MessageBoxA#16 : PROC
extrn ExitProcess#4 : PROC
.data
HelloWorld db "Welcome to SecurityTube.net!", 0
MsgTitle db "First MessageBox", 0
.code
start:
mov eax, 0
push eax
lea ebx, MsgTitle
push ebx
lea ebx, HelloWorld
push ebx
push eax
call MessageBoxA#16
push eax
call ExitProcess#4
end start
I use following command for assembling and linking
ml /c /coff helloworld.asm
link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib helloworld.obj
Program assembled perfectly. However, while linking, i got this error:
Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
LINK : fatal error LNK1104: cannot open file "kernel32.lib"
Why i am getting this error and how to mitigate it?
The command you're looking for is:
ml.exe helloworld.asm
/coff
/link
/subsystem:windows
/defaultlib:kernel32.lib
/defaultlib:user32.lib
/libpath:C:\...somewhere...
helloworld.obj
Note that instead of running ml first with the /c switch (which assembles only without linking), and then running link, I've just combined it all into a single command line. This will run MASM to assemble the code, and then immediately link it.
The magic sauce is the /link switch, which passes every argument that comes after it to the linker.
Notice the other new switch that you did not have: /libpath. This is the one that tells the linker where the LIB files can be found. They are part of the Windows SDK, so you'll need to locate that directory on your hard disk and substitute that path for C:\...somewhere.... The exact location differs depending on which version of the SDK you have installed and how you installed it (separately, or as part of Visual Studio). If you don't have the SDK, download it here for Windows 10, or for earlier versions. (Note that the latest version is sufficient; you do not need to download every version. It supports multi-targeting.)
The documentation for MASM is all available online, including a comprehensive listing of command line options. Same thing for the linker; its options are here.
An even easier solution would be to open the Visual Studio Command Prompt and do all of your assembling and linking from there. This actually runs a batch file that sets up the environment for you so that you don't have to worry about specifying the path to all of the required SDK files (headers, libraries, etc.). You'll find this in your Start menu, or manually run:
C:\Program Files (x86)\Microsoft Visual Studio x.x\VC\bin\vcvars32.bat
to set up a 32-bit build environment.
Did you check Visual Studio's directory structure and look for $(WindowsSdkDir)\lib to see if they exist?
If not install http://msdn.microsoft.com/en-us/windows/desktop/bg162891.aspx

Resources