gpt4 book ai didi

nasm - Mach-O 64位格式不支持32位绝对地址。 NASM访问阵列

转载 作者:行者123 更新时间:2023-12-04 17:43:36 25 4
gpt4 key购买 nike

使用以下命令在我的Mac计算机上运行此代码:

nasm -f macho64 -o max.a maximum.asm

这是我尝试在计算机上运行的代码,该代码在数组中找到最大的数字。
section .data

data_items:
dd 3,67,34,222,45,75,54,34,44,33,22,11,66,0

section .text

global _start

_start:
mov edi, 0
mov eax, [data_items + edi*4]
mov ebx, eax

start_loop:
cmp eax, 0
je loop_exit
inc edi
mov eax, [data_items + edi*4]
cmp eax, ebx
jle start_loop

mov ebx, eax
jmp start_loop

loop_exit:

mov eax, 1
int 0x80

错误:
maximum.asm:14: error: Mach-O 64-bit format does not support 32-bit absolute addresses
maximum.asm:21: error: Mach-O 64-bit format does not support 32-bit absolute addresses

最佳答案

首先,注意带有macho64输出格式64-bit absolute addressing (NASM 2.13.02+)RIP-relative in NASM 2.11.08的NASM错误。不建议使用64位绝对寻址,因此,即使对于有故障的NASM 2.13.02及更高版本,此答案也应适用。 (这些错误不会导致此错误,它们会导致在运行时使用错误的地址。)
[data_items + edi*4]是32位寻址模式。甚至[data_items + rdi*4]也只能使用32位绝对位移,因此它也不起作用。请注意,使用地址作为类似于 cmp rdi, data_items is also a problem的32位(符号扩展)立即数:仅mov允许64位立即数。

OS X上的的64位代码不能完全使用的32位绝对地址。可执行文件在高于4GiB的基地址上加载,因此标签地址仅是普通格式,不适合带有零或符号扩展名的32位整数。无论您是否需要与RIP无关,RIP相对寻址都是最佳/最有效的解决方案。

在NASM中,文件顶部 default rel 将使所有[]内存操作数更喜欢RIP相对寻址。另请参见NASM手册中的Section 3.3 Effective Addresses

default rel                     ; near the top of file; affects all instructions

my_func:
...
mov ecx, [data_items] ; uses the default: RIP-relative

;mov ecx, [abs data_items] ; override to absolute [disp32], unusuable
mov ecx, [rel data_items] ; explicitly RIP-relative

但是相对于RIP的 is only possible when there are no other registers involved,因此 要为静态数组建立索引,您需要首先在寄存器中获取地址。使用相对于RIP的 lea rsi, [rel data_items]
 lea   rsi, [data_items]    ; can be outside the loop
...
mov eax, [rsi + rdi*4]

或者,您可以在循环内部使用 add rsi, 4并使用更简单的寻址模式,例如 mov eax, [rsi]

请注意, mov rsi, data_items可用于将地址添加到寄存器中,但是您不希望这样做,因为它效率较低。

从技术上讲,阵列+ -2GiB内的任何地址都可以使用,因此,如果您有多个阵列,则可以相对于一个公共(public)基址来寻址其他阵列,只需将一个寄存器与一个指针绑定(bind)即可。例如 lea rbx, [arr1]/.../ mov eax, [rbx + rdi*4 + arr2-arr1]Relative Addressing errors - Mac 10.10提到Agner Fog的“优化程序集”指南中有一些数组寻址的示例,包括一个使用 __mh_execute_header作为引用点的示例。 (该问题中的代码看起来像是另一种尝试,将这个32位Linux示例从PGU本书移植到64位OS X,同时首先学习了asm。)

请注意,在Linux上,位置相关的可执行文件被加载到虚拟地址空间的低32位中,因此您将在Linux示例中看到诸如 mov eax, [array + rdi*4]mov edi, symbol_name之类的代码,或者在 http://gcc.godbolt.org/上看到编译器输出。 gcc -pie -fPIE将在Linux和 is the default on many recent distros上创建与位置无关的可执行文件,但不能创建Godbolt。

这在MacOS上无济于事,但如果有人对他们在其他OS上看到的代码感到困惑,或者为什么AMD64架构师费心地允许在x86-64上完全使用 [disp32]寻址模式,则我会提及它。

顺便说一句, 倾向于在64位代码中使用64位寻址模式。例如使用 [rsi + rdi*4],而不是 [esi + edi*4]。您通常不希望将指针截断为32位,并且它花费了额外的地址大小前缀来进行编码。

同样,您应该使用 syscall而不是 int 0x80进行64位系统调用。 What are the calling conventions for UNIX & Linux system calls on i386 and x86-64表示传递args的寄存器的区别。

脚注1:
OS X支持64位绝对寻址,但仅在位置相关的可执行文件(非PIE)中支持。此相关问题 x64 nasm: pushing memory addresses onto the stack & call function包含一个使用 ld链接到的 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

因此,链接器检查是否使用了64位绝对重定位,如果使用,则禁用创建与位置无关的可执行文件。 PIE可以受益于 ASLR的安全性。我认为共享库代码必须始终与OS X无关。我不知道是否允许跳转表或以数据为指针的其他情况(即由动态链接器修复),或者如果您不制作与位置相关的可执行文件,是否需要在运行时初始化它们。
mov r64, imm64较大(10个字节),但不比 lea r64, [RIP_rel32](7个字节)快。

因此,您可以使用 mov rsi, qword data_items代替相对于RIP的LEA,LEA的运行速度几乎一样快,并且在代码缓存和uop缓存中占用的空间更少。 64位立即数也对Sandybridge-family( http://agner.org/optimize/)进行uop缓存获取:这需要2个周期来读取uop缓存行,而不是1个周期。

x86还具有一种 mov形式,可从64位绝对地址加载/存储到64位绝对地址,但仅适用于AL/AX/EAX/RAX。参见 http://felixcloutier.com/x86/MOV.html。您也不希望这样做,因为它比 mov eax, [rel foo]更大且不快。

(相关: an AT&T syntax version of the same question)

关于nasm - Mach-O 64位格式不支持32位绝对地址。 NASM访问阵列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47300844/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com