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
Related
I have the following assembly code that i got from a x86 assembly tutorial online:
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
I saved the above code in a file "hello.asm"
now when i compile and link it in my terminal, i get the following error!
root#mac:~# nasm -f macho hello.asm && gcc -o hello hello.o
ld: warning: ignoring file hello.o, file was built for i386 which is not the architecture being linked (x86_64): hello.o
Undefined symbols for architecture x86_64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The code you have is valid Linux code. However, it is not valid MacOS code. This is because the system interrupt int 0x80 is meant to call the Linux system kernel not the MacOS one. If you have a older version of MacOS that is Linux based this might still work.
The other problem is that this code is 32-bit and you are compiling it like 64-bit code. To solve this you should add -m32 to the gcc command.
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
I'm trying to link a 32Bit simple object file with ld, but I only get this error message
ld: warning: option -m is obsolete and being ignored
ld: file not found: i386
On first sight I thought it was just a simple syntax error, because i386 is not a file, it should be the architecture. My command line looks like this:
ld add64.o -m i386 -static -o JulianTest
According to the man pages this syntax should be correct.
Maybe I should also mention that I used :
nasm -g -f elf32 myfile.asm
to compile and that I'm on a 64Bit-System (OS X), furthermore this is my add64.asm:
section .data
section .bss
section .text
global _start
mov eax, 0x11111111
mov ebx, 0x22222222
mov ecx, 0x33333333
mov edx, 0x44444444
add ebx, edx
adc eax, ecx
int 80h
Any thoughts?
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?
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.