mov rax,[res] does not work in macho64 [duplicate] - macos

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.
My code:
section .data
res db 0
section .text
global _main
extern _printf
extern _scanf
_main
..blablabla.....
mov rax,[res]
..blablbabla....
ret
And error: Mach-O 64-bit format does not support 32-bit absolute addresses on mov rax,[res].
So, in macho64, I can't link res, in [res]?
What should I do?

I don't know macho64 format, but there are alternatives to mov rax,[res]:
mov rax,res
mov rax,[rax]
Or using RIP-relative addressing:
mov rax,[rel res]

Related

Why is my NASM assembly not outputting to the console? [duplicate]

This question already has answers here:
Hello world in NASM with LINK.EXE and WinAPI
(1 answer)
How to write hello world in assembly under Windows?
(9 answers)
Windows system calls [duplicate]
(1 answer)
Closed 8 months ago.
Assuming I hate myself and want to avoid external libraries as much as possible, I am trying to write hello world assembly. From what little I understand, in Windows we should link with the kernel32.dll and output from that. Any ideas why my code is not outputting?
code:
extern ExitProcess
extern WriteFile
section .text
global Start ;must be declared for linker (ld)
Start: ;tells linker entry point
mov rdx,len ;message length
mov rcx,msg ;message to write
mov rbx,1 ;file descriptor (stdout)
mov rdx,4 ;system call number (sys_write)
int WriteFile ;call kernel
mov rax,1 ;system call number (sys_exit)
int ExitProcess ;call kernel
section .data
msg db 'Hello, world!', 0xa ;string to be printed
len equ $ - msg ;length of the string
instructions ran:
nasm -f win64 -o hello_world.obj hello_world.asm
golink hello_world.obj kernel32.dll
hello_world.exe
no errors or warnings on running the commands.
Thanks in advance!

How to print to console in 64-Bit Windows NASM in without stdio or Visual Studio? [duplicate]

This question already has answers here:
How To Properly call 64 Bit Windows API In Assembly
(1 answer)
Hello world in NASM with LINK.EXE and WinAPI
(1 answer)
Setting up an assembler on 64-bit Windows [closed]
(2 answers)
Is it possible to output a string to the console in C without including the standard library?
(2 answers)
Closed 2 years ago.
I am trying to write a 64-bit NASM assembly program in Windows to simply print some output to the console. I would like to do this with the most pure assembly possible, so that excludes any standard C libraries. I'm also trying to automate the assembly and linking process, so opening Visual Studio and doing it manually is not an option.
I know that I have to use the Windows APIs like _GetStdHandle and _WriteFile, but I can't figure out how to link those libraries, or how to use them in a 64-bit program.
This is the "Hello World" assembly code I am trying to run:
global _main
extern _GetStdHandle#4
extern _WriteFile#20
extern _ExitProcess#4
section .text
_main:
; DWORD bytes;
mov ebp, esp
sub esp, 4
; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
push -11
call _GetStdHandle#4
mov ebx, eax
; WriteFile( hstdOut, message, length(message), &bytes, 0);
push 0
lea eax, [ebp-4]
push eax
push (message_end - message)
push message
push ebx
call _WriteFile#20
; ExitProcess(0)
push 0
call _ExitProcess#4
; never here
hlt
message:
db 'Hello, World', 10
message_end:
But I'm not sure how to link the Windows 64-bit APIs to the program. I have also been getting this error: "instruction not supported in 64-bit mode" for the instruction "push eax". I'm just not sure how to re-write this code for 64-bit.
This is the batch program I am using to assemble and link the program:
nasm -f win64 HelloWorld.asm -o HelloWorld.obj &&^
"C:\Program Files\GoLink\GoLink.exe" /console /entry _main HelloWorld.obj /fo HelloWorld.exe &&^
HelloWorld.exe
Can anyone walk me through the steps required to get this program to run with the given constraints?

Printing hello world in nasm windows

What would the equivalent nasm would be in windows without using any libraries?
section .text
global _start
_start:
mov edx,len
mov ecx,msg
mov ebx,1
mov eax,4
int 0x80
mov eax,1
int 0x80
section .data
msg db 'Hello, world!', 0xa
len equ $ - msg
I read that _start is replaced with _main in windows but what about the system call? I found this table but im not sure which register gets what argument:
http://j00ru.vexillium.org/syscalls/nt/32/
Im especially confused about how to understand the system calls in windows because in linux its really clear what to do:
https://syscalls.kernelgrok.com/
The documentation for windows assembly, especially the system calls seems really really poor.

Mach-O 64-bit format does not support 32-bit absolute addresses. NASM [duplicate]

This question already has answers here:
x64 nasm: pushing memory addresses onto the stack & call function
(3 answers)
Assembler Error: Mach-O 64 bit does not support absolute 32 bit addresses
(2 answers)
Mach-O 64-bit format does not support 32-bit absolute addresses. NASM Accessing Array
(1 answer)
Closed 4 years ago.
When I use nasm -f macho64 asm1.asm I get the following error:
asm1.asm:14: error: Mach-O 64-bit format does not support 32-bit absolute addresses
This is asm1.asm
SECTION .data ;initialized data
msg: db "Hello world, this is assembly", 10, 0
SECTION .text ;asm code
extern printf
global _main
_main:
push rbp
mov rbp, rsp
push msg
call printf
mov rsp, rbp
pop rbp
ret
I'm really new to assembly and barely know what these commands do. Any idea what's wrong here?
Mac OS X, like other UNIX/POSIX systems, uses a different calling convention for 64-bit code. Instead of pushing all the arguments to the stack, it uses RDI, RSI, RDX, RCX, R8, and R9 for the first 6 arguments. So instead of using push msg, you'll need to use something like mov RDI, msg.
Besides what Drew McGowen points out, rax needs to be zeroed (no vector parameters).
But -f win64 or -f elf64 will work on this code. I suspect a bug in -f macho64 (but I'm not sure what macho64 is "supposed" to do). Until this gets fixed(?), the workaround is to use default rel or mov rdi, rel msg. I "think" that'll work for ya.

x64 nasm: pushing memory addresses onto the stack & call function

I'm pretty new to x64-assembly on the Mac, so I'm getting confused porting some 32-bit code in 64-bit.
The program should simply print out a message via the printf function from the C standart library.
I've started with this code:
section .data
msg db 'This is a test', 10, 0 ; something stupid here
section .text
global _main
extern _printf
_main:
push rbp
mov rbp, rsp
push msg
call _printf
mov rsp, rbp
pop rbp
ret
Compiling it with nasm this way:
$ nasm -f macho64 main.s
Returned following error:
main.s:12: error: Mach-O 64-bit format does not support 32-bit absolute addresses
I've tried to fix that problem byte changing the code to this:
section .data
msg db 'This is a test', 10, 0 ; something stupid here
section .text
global _main
extern _printf
_main:
push rbp
mov rbp, rsp
mov rax, msg ; shouldn't rax now contain the address of msg?
push rax ; push the address
call _printf
mov rsp, rbp
pop rbp
ret
It compiled fine with the nasm command above but now there is a warning while compiling the object file with gcc to actual program:
$ gcc main.o
ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not
allowed in code signed PIE, but used in _main from main.o. To fix this warning,
don't compile with -mdynamic-no-pic or link with -Wl,-no_pie
Since it's a warning not an error I've executed the a.out file:
$ ./a.out
Segmentation fault: 11
Hope anyone knows what I'm doing wrong.
The 64-bit OS X ABI complies at large to the System V ABI - AMD64 Architecture Processor Supplement. Its code model is very similar to the Small position independent code model (PIC) with the differences explained here. In that code model all local and small data is accessed directly using RIP-relative addressing. As noted in the comments by Z boson, the image base for 64-bit Mach-O executables is beyond the first 4 GiB of the virtual address space, therefore push msg is not only an invalid way to put the address of msg on the stack, but it is also an impossible one since PUSH does not support 64-bit immediate values. The code should rather look similar to:
; this is what you *would* do for later args on the stack
lea rax, [rel msg] ; RIP-relative addressing
push rax
But in that particular case one needs not push the value on the stack at all. The 64-bit calling convention mandates that the fist 6 integer/pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9, exactly in that order. The first 8 floating-point or vector arguments go into XMM0, XMM1, ..., XMM7. Only after all the available registers are used or there are arguments that cannot fit in any of those registers (e.g. a 80-bit long double value) the stack is used. 64-bit immediate pushes are performed using MOV (the QWORD variant) and not PUSH. Simple return values are passed back in the RAX register. The caller must also provide stack space for the callee to save some of the registers.
printf is a special function because it takes variable number of arguments. When calling such functions AL (the low byte of RAX) should be set to the number of floating-point arguments, passed in the vector registers. Also note that RIP-relative addressing is preferred for data that lies within 2 GiB of the code.
Here is how gcc translates printf("This is a test\n"); into assembly on OS X:
xorl %eax, %eax # (1)
leaq L_.str(%rip), %rdi # (2)
callq _printf # (3)
L_.str:
.asciz "This is a test\n"
(this is AT&T style assembly, source is left, destination is right, register names are prefixed with %, data width is encoded as a suffix to the instruction name)
At (1) zero is put into AL (by zeroing the whole RAX which avoids partial-register delays) since no floating-point arguments are being passed. At (2) the address of the string is loaded in RDI. Note how the value is actually an offset from the current value of RIP. Since the assembler doesn't know what this value would be, it puts a relocation request in the object file. The linker then sees the relocation and puts the correct value at link time.
I am not a NASM guru, but I think the following code should do it:
default rel ; make [rel msg] the default for [msg]
section .data
msg: db 'This is a test', 10, 0 ; something stupid here
section .text
global _main
extern _printf
_main:
push rbp ; re-aligns the stack by 16 before call
mov rbp, rsp
xor eax, eax ; al = 0 FP args in XMM regs
lea rdi, [rel msg]
call _printf
mov rsp, rbp
pop rbp
ret
No answer yet has explained why NASM reports
Mach-O 64-bit format does not support 32-bit absolute addresses
The reason NASM won't do this is explained in Agner Fog's Optimizing Assembly manual in section 3.3 Addressing modes under the subsection titled 32-bit absolute addressing in 64 bit mode he writes
32-bit absolute addresses cannot be used in Mac OS X, where addresses are above 2^32 by
default.
This is not a problem on Linux or Windows. In fact I already showed this works at static-linkage-with-glibc-without-calling-main. That hello world code uses 32-bit absolute addressing with elf64 and runs fine.
#HristoIliev suggested using rip relative addressing but did not explain that 32-bit absolute addressing in Linux would work as well. In fact if you change lea rdi, [rel msg] to lea rdi, [msg] it assembles and runs fine with nasm -efl64 but fails with nasm -macho64
Like this:
section .data
msg db 'This is a test', 10, 0 ; something stupid here
section .text
global _main
extern _printf
_main:
push rbp
mov rbp, rsp
xor al, al
lea rdi, [msg]
call _printf
mov rsp, rbp
pop rbp
ret
You can check that this is an absolute 32-bit address and not rip relative with objdump. However, it's important to point out that the preferred method is still rip relative addressing. Agner in the same manual writes:
There is absolutely no reason to use absolute addresses for simple memory operands. Rip-
relative addresses make instructions shorter, they eliminate the need for relocation at load
time, and they are safe to use in all systems.
So when would use use 32-bit absolute addresses in 64-bit mode? Static arrays is a good candidate. See the following subsection Addressing static arrays in 64 bit mode. The simple case would be e.g:
mov eax, [A+rcx*4]
where A is the absolute 32-bit address of the static array. This works fine with Linux but once again you can't do this with Mac OS X because the image base is larger than 2^32 by default. To to this on Mac OS X see example 3.11c and 3.11d in Agner's manual. In example 3.11c you could do
mov eax, [(imagerel A) + rbx + rcx*4]
Where you use the extern reference from Mach O __mh_execute_header to get the image base. In example 3.11c you use rip relative addressing and load the address like this
lea rbx, [rel A]; rel tells nasm to do [rip + A]
mov eax, [rbx + 4*rcx] ; A[i]
According to the documentation for the x86 64bit instruction set http://download.intel.com/products/processor/manual/325383.pdf
PUSH only accepts 8, 16 and 32bit immediate values (64bit registers and register addressed memory blocks are allowed though).
PUSH msg
Where msg is a 64bit immediate address will not compile as you found out.
What calling convention is _printf defined as in your 64bit library?
Is it expecting the parameter on the stack or using a fast-call convention where the parameters on in registers? Because x86-64 makes more general purpose registers available the fast-call convention is used more often.

Resources