qwe*_*rtz 5 macos assembly gcc x86-64 nasm
我对Mac上的x64-assembly很新,所以我很困惑在64位中移植一些32位代码.
程序应该只通过printfC标准库中的函数打印出一条消息.
我已经开始使用这段代码:
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
Run Code Online (Sandbox Code Playgroud)
用这种方式用nasm编译它:
$ nasm -f macho64 main.s
Run Code Online (Sandbox Code Playgroud)
返回以下错误:
main.s:12: error: Mach-O 64-bit format does not support 32-bit absolute addresses
Run Code Online (Sandbox Code Playgroud)
我试图修复问题字节,将代码更改为:
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
Run Code Online (Sandbox Code Playgroud)
它使用nasm上面的命令编译好,但现在在将目标文件编译gcc为实际程序时出现警告:
$ 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
Run Code Online (Sandbox Code Playgroud)
因为它是一个警告而不是错误我已经执行了a.out文件:
$ ./a.out
Segmentation fault: 11
Run Code Online (Sandbox Code Playgroud)
希望有人知道我做错了什么.
64位OS X ABI完全符合System V ABI - AMD64架构处理器补充资料.它的代码模型非常类似于小位置无关代码模型(PIC),这里解释了不同之处.在该代码模型中,使用RIP相对寻址直接访问所有本地和小数据.正如Z boson的评论中所指出的,64位Mach-O可执行文件的图像库超出了虚拟地址空间的前4 GiB,因此push msg不仅是将地址msg放在堆栈上的无效方式,而且因为PUSH不支持64位立即值,所以也是不可能的.代码看起来应该类似于:
; this is what you *would* do for later args on the stack
lea rax, [rel msg] ; RIP-relative addressing
push rax
Run Code Online (Sandbox Code Playgroud)
但是在那种特殊情况下,根本不需要在堆栈上推送值.64位调用约定强制要求的拳头6整数/指针参数在寄存器传递RDI,RSI,RDX,RCX,R8,和R9,恰好以该顺序.前8个浮点或载体参数进入XMM0,XMM1,... XMM7.仅在使用所有可用寄存器或存在不能适合任何这些寄存器的参数(例如,80位long double值)之后,才使用堆栈.使用MOV(QWORD变体)执行64位立即推送而不是PUSH.简单的返回值将传回RAX寄存器中.调用者还必须为被调用者提供堆栈空间以保存一些寄存器.
printf是一个特殊的函数,因为它需要可变数量的参数.调用此类函数时,AL应将其设置为浮点参数的数量,并在向量寄存器中传递.另请注意,RIP对于位于代码2 GiB内的数据,首选相对寻址.
以下是在OS X上gcc转换printf("This is a test\n");为汇编的方式:
xorl %eax, %eax # (1)
leaq L_.str(%rip), %rdi # (2)
callq _printf # (3)
L_.str:
.asciz "This is a test\n"
Run Code Online (Sandbox Code Playgroud)
(这是AT&T样式程序集,源是左,目标是正确的,寄存器名称是前缀%,数据宽度编码为指令名称的后缀)
在(1)零投入AL,因为没有浮点参数被传递.在(2)加载字符串的地址RDI.注意该值实际上是与当前值的偏移量RIP.由于汇编程序不知道该值是什么,因此它将重定位请求放在目标文件中.然后链接器会看到重定位并在链接时放入正确的值.
我不是NASM大师,但我认为以下代码应该这样做:
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
Run Code Online (Sandbox Code Playgroud)
还没有答案解释为什么 NASM 报告
Mach-O 64-bit format does not support 32-bit absolute addresses
Run Code Online (Sandbox Code Playgroud)
NASM 不会这样做的原因在Agner Fog 的 Optimizing Assembly手册中的3.3节寻址模式中解释了他写的标题为64 位模式下的32 位绝对寻址的小节
32 位绝对地址不能在 Mac OS X 中使用,默认情况下地址在 2^32 以上。
这在 Linux 或 Windows 上不是问题。事实上,我已经在static-linkage-with-glibc-without-calling-main展示了这个作品。hello world 代码使用 elf64 的 32 位绝对寻址并且运行良好。
@HristoIliev 建议使用 rip 相对寻址,但没有解释 Linux 中的 32 位绝对寻址也可以使用。事实上,如果你改变它lea rdi, [rel msg],lea rdi, [msg]它会组装并运行良好,nasm -efl64但会失败nasm -macho64
像这样:
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
Run Code Online (Sandbox Code Playgroud)
您可以检查这是一个绝对的 32 位地址,而不是 rip 相对objdump。但是,重要的是要指出首选方法仍然是 rip 相对寻址。Agner 在同一手册中写道:
绝对没有理由对简单的内存操作数使用绝对地址。相对地址使指令更短,它们消除了加载时重定位的需要,并且可以安全地在所有系统中使用。
那么什么时候在 64 位模式下使用 32 位绝对地址呢?静态数组是一个不错的选择。请参阅以下小节在 64 位模式下寻址静态数组。简单的情况是例如:
mov eax, [A+rcx*4]
Run Code Online (Sandbox Code Playgroud)
其中 A 是静态数组的绝对 32 位地址。这在 Linux 上工作得很好,但在 Mac OS X 上你又不能这样做,因为默认情况下图像库大于 2^32。要在 Mac OS X 上进行此操作,请参阅 Agner 手册中的示例 3.11c 和 3.11d。在示例 3.11c 中,您可以执行
mov eax, [(imagerel A) + rbx + rcx*4]
Run Code Online (Sandbox Code Playgroud)
使用 Mach O 中的 extern 引用__mh_execute_header来获取图像库的地方。在示例 3.11c 中,您使用 rip 相对寻址并像这样加载地址
lea rbx, [rel A]; rel tells nasm to do [rip + A]
mov eax, [rbx + 4*rcx] ; A[i]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5882 次 |
| 最近记录: |