I have a simple Hello World program for Windows in pure x86 assembly code that I have compiled and linked with nasm and ld. The problem I am running into is that I can't get DWARF debugging to work. I am using gdb from Mingw64 (i686-posix-dwarf-rev1). This same problem happens if I use gcc to link instead of ld. But, the program builds fine, and if I use STABS debugging, then everything is fine and dandy.
EDIT: Oops, I completely forgot to give the error that gdb shows.
...Dwarf Error: bad offset (0x407000) in compilation unit header (offset 0x0
+ 6) [in module C:\Projects\AsmProjects\HelloWorldWin32\bin\x86\hello32.exe]
(no debugging symbols found)...done
The versions of each program are:
gdb 7.10.1
nasm 2.12.02
ld 2.25
gcc 6.2.0
These are the flags I'm sending to nasm: -f elf32 -Fdwarf -g
These are the flags for gcc link: -o $(BDIR)/x86/$#.exe $^ -L$(Mingw64-x86libs) -lkernel32 -luser32
And these are from ld link:
-mi386pe -o $(BDIR)/x86/$#.exe $^ -L$(Mingw64-x86libs) -lkernel32 -luser32
I have a pretty big makefile, so I'm trying to give the least information that is absolutely neccessary.
Here is the source code for the program:
global _main
extern _GetStdHandle#4
extern _WriteFile#20
extern _ExitProcess#4
section .text
_main:
push ebp
mov ebp,esp
; GetstdHandle( STD_OUTPUT_HANDLE)
push -11
call _GetStdHandle#4
mov ebx, eax
; WriteFile( hstdOut, message, length(message), &bytes, 0);
push 0
push esp
push message_end
push message
push ebx
call _WriteFile#20
; ExitProcess(0)
push 0
call _ExitProcess#4
section .data
message db 'Hello, World',10
message_end equ $ - message
This is not a proper answer but was too long for the comment section.
I compiled on Ubuntu and then ran dwarfdump
It gave an error that may be related to the offset error.
dwarfdump ERROR: dwarf_get_globals: DW_DLE_PUBNAMES_VERSION_ERROR (123)
From a similar error on LLVM, I conclude that the dwarf version information is possibly corrupt or unsupported.
This post indicates that the dwarf information is sensitive to the proper section names. The example appears to have the section names right however.
Have you tried a 64-bit version? Perhaps a clue will appear.
This program appears to work fine Ubuntu. Can you try it on Mingw64?
section .text
global _start ;must be declared for linker (ld)
_start: ;tell 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 ;our dear string
len equ $ - msg ;length of our dear string
Related
This is my first ever attempt at programming with assembly. I'm using a 64 bit Mac OS. I'm also using NASM. I've done a lot of looking around for a solution, but I can't find anything that works for my machine.
Can anyone help me solve this problem? Here is the code and error, thanks!
hello.asm
global start
section .text
start:
mov rax, 1
mov rdi, 1
mov rsi, message
mov rdx, 13
syscall
mov eax, 60
xor rdi, rdi
syscall
message:
db "Hello, World", 10
my attempt at executing:
nasm -f macho64 hello.asm -o hello.o
ld -arch i386 -o hello hello.o
./hello
the error
ld: warning: -macosx_version_min not specified, assuming 10.10
ld: warning: ignoring file hello.o, file was built for unsupported file format ( 0xCF 0xFA 0xED 0xFE 0x07 0x00 0x00 0x01 0x03 0x00 0x00 0x00 0x01 0x00 0x00 0x00 ) which is not the architecture being linked (i386): hello.o
Undefined symbols for architecture i386:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture i386
The reason for your linker error is that you created a 64-bit macho object using NASM, but then targeted i386 for the executable. What you likely were after was a 64-bit executable, which could be done by removing -arch like this:
ld -o hello hello.o
As for your segfault when running your program, it seems that you likely followed a tutorial that may have been designed for Linux. OS/X isn't base upon Linux, it derived from BSD so the Syscalls are different. We could tell you were using Linux Syscalls because syscall 1 is sys_write and sys_exit is rax = 60. This unfortunately isn't the same for OS/X. In 64-bit OS/X code sys_exit is rax=0x20000001 and sys_write is rax=0x20000004 .
Your code would have to be changed to:
global start
section .data
message: db "Hello, World", 10
section .text
start:
mov rax, 0x20000004
mov rdi, 1
mov rsi, message
mov rdx, 13
syscall
mov rax, 0x20000001
xor rdi, rdi
syscall
You'll also observe I explicitly declared a .data section and placed your variable in it. In some environments it may cause problems if data variables are placed in the code.
If creating 32-bit code on OS/X (you aren't in this case) the Syscalls have 0x20000000 subtracted from each. So in 32-bit OS/X code sys_exit is eax=0x1 and sys_write is eax=0x4 .
A reference for all the Syscalls (and their parameters) on OS/X can be found in this Apple information. Just add 0x20000000 to each number in the first column of the chart for 64-bit assembler code.
You probably want to find a 64-bit OS/X tutorial about Syscalls. This is a simple one
This little program works fine on OS X, using nasm:
global _main
extern _puts
section .text
default rel
_main:
push rbp
lea rdi, [message]
call _puts
pop rbp
ret
message:
db 'Hello, world', 0
Here's how it runs:
$ nasm -fmacho64 hello.asm && gcc hello.o && ./a.out
Hello, world
But if I replace the LEA instruction (with a memory operand) with an equivalent MOV immediate:
global _main
extern _puts
section .text
default rel
_main:
push rbp
mov rdi, message ; <---- Should have same effect as lea rdi, [message]
call _puts
pop rbp
ret
message:
db 'Hello, world', 0
The program will run but with a warning message, that I know has been asked about before on Stack Overflow:
$ nasm -fmacho64 hello.asm && gcc hello.o && ./a.out
ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, but used in _main from hello.o. To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie
Hello, world
My question is why does this warning occur? I see the error is complaining about the linker not liking absolute addressing; however the MOV command is clearly using an immediate operand, not an absolute address! Is the warning mislabeled? I'm puzzled that
As an aside, this distinction does not happen under Linux. Removing default rel and the underscores on main and puts gives me a warning-free run on Ubuntu. What is OS X doing differently here? Is it a case of the assembler default configurations being set differently? Or is it something weird like OS X following AMD's ABI more closely than Ubuntu?
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.
When attempting to run the following assembly program:
.globl start
start:
pushq $0x0
movq $0x1, %rax
subq $0x8, %rsp
int $0x80
I am receiving the following errors:
dyld: no writable segment
Trace/BPT trap
Any idea what could be causing this? The analogous program in 32 bit assembly runs fine.
OSX now requires your executable to have a writable data segment with content, so it can relocate and link your code dynamically. Dunno why, maybe security reasons, maybe due to the new RIP register. If you put a .data segment in there (with some bogus content), you'll avoid the "no writable segment" error. IMO this is an ld bug.
Regarding the 64-bit syscall, you can do it 2 ways. GCC-style, which uses the _syscall PROCEDURE from libSystem.dylib, or raw. Raw uses the syscall instruction, not the int 0x80 trap. int 0x80 is an illegal instruction in 64-bit.
The "GCC method" will take care of categorizing the syscall for you, so you can use the same 32-bit numbers found in sys/syscall.h. But if you go raw, you'll have to classify what kind of syscall it is by ORing it with a type id. Here is an example of both. Note that the calling convention is different! (this is NASM syntax because gas annoys me)
; assemble with
; nasm -f macho64 -o syscall64.o syscall64.asm && ld -lc -ldylib1.o -e start -o syscall64 syscall64.o
extern _syscall
global start
[section .text align=16]
start:
; do it gcc-style
mov rdi, 0x4 ; sys_write
mov rsi, 1 ; file descriptor
mov rdx, hello
mov rcx, size
call _syscall ; we're calling a procedure, not trapping.
;now let's do it raw
mov rax, 0x2000001 ; SYS_exit = 1 and is type 2 (bsd call)
mov rdi, 0 ; Exit success = 0
syscall ; faster than int 0x80, and legal!
[section .data align=16]
hello: db "hello 64-bit syscall!", 0x0a
size: equ $-hello
check out http://www.opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/syscall_sw.h for more info on how a syscall is typed.
The system call interface is different between 32 and 64 bits. Firstly, int $80 is replaced by syscall and the system call numbers are different. You will need to look up documentation for a 64-bit version of your system call. Here is an example of what a 64-bit program may look like.
I’d like to know how can I do a simple assembly program for Mac OS X that shows a window on the screen and put some coloured text on that window. The code may call some Carbon or Cocoa APIs. I need some code for the nasm sintaxe.
I saw in http://snipplr.com/view/29150/assembly-code-nasm-for-mac--hello-world the next code that works fine, but it´s not graphic.
; Hello World in assembly for mac
;
; nasm -f macho hello.asm
; ld -e _start -o hello hello.o
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
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
Thanks for any help
This is not Carbon as requested in the comments in the previous answers, but it may help you get a step further ahead in your noble pursuit:
http://cocoawithlove.com/2010/09/minimalist-cocoa-programming.html
You can call Carbon APIs with call like this:
call _CreateNewWindow
You can pass arguments also, but I'm unsure how to do that. Probably pushed onto the stack in reversed order just before the call:
push arg4
push arg3
push arg2
push arg1
call _CreateNewWindow
You can look in how you C code compiles into assembly, like this:
$ clang myCarbonCode.c -S -O -o myCarbonCode.s