I am trying to learn x86 assembly on Windows. I can assemble and link a program successfully using:
nasm -f win32 -g sandbox.asm -l sandbox.lst
ld -mi386pe -o sandbox.exe sandbox.obj
But when I try running my program with gdb, it says that it can't find the debug symbols. Nasm says that only the "null" debug symbol format is available for win32. Does this mean that it can't generate debug symbols for windows? If so, then how can I debug my program on windows?
Here is the example program that I am using:
section .data
section .bss
section .text
global start
start:
mov ebp, esp
mov eax, 0
ret
You must specify the debugging format to include in your binary (sometimes there is not one by default)
try -gcv8 instead of -g
Related
I decided to learn assembly today, because it seemed like it's a pretty powerfull tool, but I didn't know where to start learning it, so I googled it and found this:
https://www.tutorialspoint.com/assembly_programming
It told me to install NASM and MinGW for compiling and linking, so I downloaded and installed it and made sure that both of them are working properly.
I copied the given code
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov edx,len ;message length
mov ecx,msg ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db 'Hello, world!', 0xa ;string to be printed
len equ $ - msg ;length of the string
and pasted it into an empty document called "hello.asm" and compiled it by writing
nasm -f elf hello.asm
(later nasm -f win32 hello.asm)
and afterwards
ld hello.o -o hello.exe
(later ld hello.obj -o hello.exe)
and it successfully created a .exe file both times , but when I tried to execute it, it only opened the windows command prompt and a new window opened that said "hello.exe doesn't work anymore".
I know this won't output anything, but shouldn't it at least run ?
What did I do wrong ?
Using:
Windows 7 professional 64bit
AMD FX 4350
nasm-2.12.02
MinGW
You're going to need a different tutorial, as user tkausl pointed out this tutorial is for Linux x86_64 bit.
For windows, you can still use the NASM assembler and MinGW if you wish, but your code is going to look different because of the different calls and will also require you to use external libraries.
I recommend using the MASM for Windows however, as it is designed by Microsoft, and also included in the MASM32v8 package which has other tools. You can get MASM from here: http://www.masm32.com/
There is also a tutorial for Windows Assembly:
https://www-s.acm.illinois.edu/sigwin/old/workshops/winasmtut.pdf
However, if you are intent on using the NASM assembler, then you can refer to the answer posted by caffiend here:
How to write hello world in assembler under Windows?
I have written an assembly program that, for testing purposes, just exits. The code is as follows:
section .text
_global start
_start:
mov eax, 1
mov ebx, 0
int 0x80
The program is obviously in 32-bit; however, I am using 1 64-bit processor and operating system, so I compiled it (using nasm) and linked it as follows:
nasm -f elf exit.asm
ld -m elf_i386 -s -o exit exit.o
debugging the program with gdb, I can't list the code since there are no debugging symbols.
(gdb) list
No symbol table is loaded. Use the "file" command.
In using gcc, you can use the options -ggdb to load the symbols while compiling a c file. but since I don't how to use gcc to compile 32-bit assembly for 64-bit machines (I have searched this but can't find a solution,) I am forced to use ld. can I load the debugging symbols using ld? sorry for the long question and the excess information. Thanks in advance.
Debugging information is generated by nasm when you pass -g. Additionally, you also need to specify what type of debugging information you want (typically dwarf), which is done with the -F switch. So to assemble your file, write
nasm -f elf -F dwarf -g file.asm
then link without -s to preserve the symbol table and debugging information:
ld -m elf_i386 -o file file.o
The -s switch tells ld to "strip" the debugging info. Lose that!
I wrote a test program for learning purposes in x86 assembly using NASM as assembler and MinGW32 (ld) as linkerW.
I am working on Windows 10.
section .text
global my_start
my_start:
nop
nop
nop
nop
jmp my_start
I am using the following command for assembling:
nasm -f win32 -l main.lst main.asm
And the following command for linking:
ld -nostdlib -nostartfiles -s -o main.exe -e my_start main.obj
Now if I run the program I get an sgmentation fault error.
To find out why I used GDB for debugging and found out that windows is executing my executable at file begin where the DOS Header is laying.
So windows is trying to execute the magic number "MZ" (4d 5a) and following bytes as assembler instructions.
So, now I am very confused why this happens because I specified an entry point (-e my_start) followed by valid x86 assembler instructions.
Why exactly my executable start's execute at DOS header and not at my specified entry point in my code segment?
How I can fix this?
EDIT:
I tried now GoLink and using this linker everything is working fine:
GoLink.exe main.obj /entry my_start
I also compared the entry point of the optional header and both are equal.
But comparing both files a lot of things are different so I cannot tell what exactly is wrong so I will stick with GoLink for a while and maybe come back to this problem if I have a bit more experience.
I'm following a assembly book which uses the yasm assembler and ld linker. I'm on OSX 10.12 and I'm trying to assembly to Mach-O format. Unfortunately, I'm receiving a segmentation fault. This is the original .asm file:
BITS 64
segment .data
a dd 4
segment .bss
g resd 1
segment .text
global start
start:
push rbp
mov rbp, rsp
sub rsp, 16
xor eax, eax
leave
ret
I compile it:
yasm -f macho64 -m amd64 -l memory.lst -o memory.o memory.asm
link it:
ld memory.o -o memory
and run it in lldb, I receive this error:
thread #1: tid = 0xb3b4b, 0x0000000000000001, stop reason = EXC_BAD_ACCESS (code=1, address=0x1)
frame #0: 0x0000000000000001
error: error reading data from section __PAGEZERO
In lldb, I ran 'target modules dump sections', and I see that it's __PAGEZERO segment is defined as so:
[0x0000000000000000-0x0000000000001000) --- memory.__PAGEZERO
I looked at a normal Mach-O binary built with clang, and the __PAGEZERO segment looks like this:
[0x0000000000000000-0x0000000100000000) --- test.__PAGEZERO
I then noticed that it's actually the linker that creates the PAGEZERO segment. I believe clang uses a special linker called 'lld'. My question is:
Is my error actually caused by reading from PAGEZERO.
If so, can I tell my linker (ld) to define PAGEZERO in the correct size?
SOLVED: I changed the link command to:
ld memory.o -macosx_version_min 10.12 -lSystem -o memory
This doesn't change the PAGEZERO size, so I'm not sure how it fixed it, but it works now.
I found the following code from http://www.dreamincode.net/forums/topic/328714-my-program-keeps-crashing/.
global start
;~ msvcrt.dll
extern _printf
%define printf _printf
;~ kernel32.dll
extern ExitProcess, GetCommandLineW, LocalFree
%define GetCommandLine GetCommandLineW
;~ shell32.dll
extern CommandLineToArgvW
%define CommandLineToArgv CommandLineToArgvW
SECTION .data
message db 'Hello, World', 13, 10, 0
fmtstr db "%s", 0
fmtstrCL db "Arg","%d", " = ", "%S", 13, 10, 0
section .bss
pNumArgs resd 1
section .text
start:
call GetCommandLine
push pNumArgs
push eax
call CommandLineToArgv
mov esi, eax
mov ebx, [pNumArgs]
DisplayArgs:
dec ebx
push dword[esi + 4 * ebx]
inc ebx
push ebx
push fmtstrCL
call printf
add esp, 4 * 3
dec ebx
jnz DisplayArgs
push esi
call LocalFree
push message ; Push address of "Hello, world!" onto the stack
push fmtstr ; push address of formatter onto the stack
call printf ; Print the message
add esp, 4 * 2 ; adjust stack pointer
push 0
call ExitProcess
My goal is to learn assembly language by reading other people's code and eventually write my own. I cannot figure out how to link 32-bit assembly programs on my 64-bit windows computer.
To assemble the program I use the command:
nasm -f win32 hello32.asm -o hello32.o
To link the object file I use:
gcc hello32.o -o hello32.exe
After I issue the link command I get the following error:
C:/Program Files/mingw-w64/x86_64-5.2.0-posix-seh-rt_v4-rev0/mingw64/bin/../lib/
gcc/x86_64-w64-mingw32/5.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: i386 arc
hitecture of input file `hello32.o' is incompatible with i386:x86-64 output
hello32.o:hello32.asm:(.text+0x24): undefined reference to `_printf'
hello32.o:hello32.asm:(.text+0x3f): undefined reference to `_printf'
C:/Program Files/mingw-w64/x86_64-5.2.0-posix-seh-rt_v4-rev0/mingw64/bin/../lib/
gcc/x86_64-w64-mingw32/5.2.0/../../../../x86_64-w64-mingw32/lib/../lib/libmingw3
2.a(lib64_libmingw32_a-crt0_c.o):crt0_c.c:(.text.startup+0x2e): undefined refere
nce to `WinMain'
collect2.exe: error: ld returned 1 exit status
I am using 64-bit mingw binaries that are supposed to be compatible with making 32-bit programs. I have tried switching to 32-bit mingw binaries and I get a massive amount of undefined reference errors. I can link simple skeleton files without any problems using the above commands. I have no idea what I am doing wrong and I would appreciate any guidance someone could give me.
i386 architecture of input file `hello32.o' is incompatible with i386:x86-64 output
NASM has created a 32 bit object file, but you are trying to link a 64 bit executable. You could try to use the -m32 switch to create a 32 bit executable, but you already found out that this causes another bunch of errors. I do not have a solution for that either.
To link your executable, use a 32 bit MingW environment. I tried MinGW4.6.2 32 bit which worked well.
Alternatively, you can use the linker (link.exe) from a Microsoft Visual Studio installation.
https://github.com/afester/CodeSamples/tree/master/Asm/nasm_win32 shows a hello world example together with a Makefile which uses the Visual Studio linker. Alternatively, using gcc helloworld.obj -o hello32.exe from a MingW32 installation works also.
Two issues:
You're using the option -f win32 but asking for the object file in *.o extension. The two formats, .o and .obj are not compatible. But of course, you're free to specify your own extension, and so nasm will obediently assemble your code into a file with i386 arc format .o file.
Next, you're asking gcc to build that hello32.exe, using the file hello32.o. Effectively, you gave gcc an arc format .o file, and asked to build a 64-bit PE format executable out of it. And then (naturally) gcc complains:
i386 architecture of input file `hello32.o' is incompatible with i386:x86-64 output
which is correct.
Two ways you can fix this:
Assemble with: nasm -fwin32 hello32.asm and then, link with gcc -m32 hello32.obj -o hello32.exe
Assemble with: nasm -fobj hello32.asm and then link with alink -subsys console -oPE hello32.o. You can get alink from here.
Let me know which worked for you.
P.S. I have outlined the problems I have faced myself in this blog, hope that helps.