汇编 32 位寻址大小而不是 64 位模式下的 64 位
Assembly 32-bit addressing size instead of 64-bit in 64-bit Mode
我对 64 位模式下的 32 位寻址大小而不是 64 位寻址大小有疑问
func:
movzx eax, al ; instead of movzx rax, al
mov eax, DWORD [4 * eax + .data] ; instead of mov rax, QWORD [8 * rax + .data]
ret
.data:
DD .DATA1 ; instead of DQ
DD .DATA2 ; instead of DQ
DD .DATA3 ; instead of DQ
DD .DATA4 ; instead of DQ
.DATA1 DB 'HEY1', 0x00
.DATA2 DB 'HEY2', 0x00
.DATA3 DB 'HEY3', 0x00
.DATA4 DB 'HEY4', 0x00
它在 64 位 中是否安全?因为我认为在 64 位和这样寻址,没有问题! (我这样做是因为 .data)
我认为 .data 如果程序大小(可执行文件)小于 32 位寄存器,每个项目地址都适合大约 100 Mb 总是 !
例如,这在 x86-64 MacOS 或 Linux PIE executable 上是不安全的。程序大小不是唯一的因素,因为它不是从虚拟地址 0
开始加载的。您的程序的第一个字节可能位于 0x555555555000
之类的位置,因此无论您的程序有多小,将地址截断为 32 位都会破坏您的代码。
(在这种情况下使用 [.data + rax*4]
会导致无效的重定位链接器错误,不过,只是将 .data
用作绝对值 disp32
。32-bit absolute addresses no longer allowed in x86-64 Linux? ).但是,如果您在 RDI 中将 [edi + eax*4]
与有效指针一起使用,您可以编写 assemble 但在 PIE executable 或 MacOS executable 中崩溃的代码。 )
但是是的,默认的非 PIE Linux 代码模型将所有代码和静态数据放在虚拟地址的低 2GiB space 所以 32 位绝对符号-或零扩展数字可以表示地址。
无论您如何寻址,内存中的数据都是相同的大小,因此您的替代方案是
movzx eax, al
mov eax, DWORD [4 * eax + table_of_32bit_pointers] ; pointless
mov eax, DWORD [4 * rax + table_of_32bit_pointers] ; good
; RAX holds a zero-extended pointer.
mov rax, QWORD [8 * rax + .data]
将从不同的位置加载 8 个字节。您仍在混淆地址大小和操作数大小。
在内存中使用紧凑的 32 位指针并不意味着您在加载它们时必须使用 32 位地址大小。
在使用 movzx eax, al
. 将索引零扩展到 64 位后,没有理由使用 32 位地址大小(顺便说一句, prefer movzx ecx, al
; mov-elimination 只在不同的寄存器之间起作用。)
顺便说一句,如果你的字符串都是相同的长度,或者你可以廉价地将它们填充到固定长度,你不需要 table 指针。您可以改为只从第一个字符串 + 缩放索引的开头计算地址。例如p = .DATA1 + idx*5
在这种情况下,每个字符串的长度为 5 个字节。
lea eax, [.DATA1 + RAX + RAX*4] ; 4+1 = 5
; eax points at the selected 5-byte string buffer
此外,不要使用 .data
作为符号名称。这是一个部分的名称,所以会让人感到困惑。
我对 64 位模式下的 32 位寻址大小而不是 64 位寻址大小有疑问
func:
movzx eax, al ; instead of movzx rax, al
mov eax, DWORD [4 * eax + .data] ; instead of mov rax, QWORD [8 * rax + .data]
ret
.data:
DD .DATA1 ; instead of DQ
DD .DATA2 ; instead of DQ
DD .DATA3 ; instead of DQ
DD .DATA4 ; instead of DQ
.DATA1 DB 'HEY1', 0x00
.DATA2 DB 'HEY2', 0x00
.DATA3 DB 'HEY3', 0x00
.DATA4 DB 'HEY4', 0x00
它在 64 位 中是否安全?因为我认为在 64 位和这样寻址,没有问题! (我这样做是因为 .data)
我认为 .data 如果程序大小(可执行文件)小于 32 位寄存器,每个项目地址都适合大约 100 Mb 总是 !
例如,这在 x86-64 MacOS 或 Linux PIE executable 上是不安全的。程序大小不是唯一的因素,因为它不是从虚拟地址 0
开始加载的。您的程序的第一个字节可能位于 0x555555555000
之类的位置,因此无论您的程序有多小,将地址截断为 32 位都会破坏您的代码。
(在这种情况下使用 [.data + rax*4]
会导致无效的重定位链接器错误,不过,只是将 .data
用作绝对值 disp32
。32-bit absolute addresses no longer allowed in x86-64 Linux? ).但是,如果您在 RDI 中将 [edi + eax*4]
与有效指针一起使用,您可以编写 assemble 但在 PIE executable 或 MacOS executable 中崩溃的代码。 )
但是是的,默认的非 PIE Linux 代码模型将所有代码和静态数据放在虚拟地址的低 2GiB space 所以 32 位绝对符号-或零扩展数字可以表示地址。
无论您如何寻址,内存中的数据都是相同的大小,因此您的替代方案是
movzx eax, al
mov eax, DWORD [4 * eax + table_of_32bit_pointers] ; pointless
mov eax, DWORD [4 * rax + table_of_32bit_pointers] ; good
; RAX holds a zero-extended pointer.
mov rax, QWORD [8 * rax + .data]
将从不同的位置加载 8 个字节。您仍在混淆地址大小和操作数大小。
在内存中使用紧凑的 32 位指针并不意味着您在加载它们时必须使用 32 位地址大小。
movzx eax, al
. 将索引零扩展到 64 位后,没有理由使用 32 位地址大小(顺便说一句, prefer movzx ecx, al
; mov-elimination 只在不同的寄存器之间起作用。)
顺便说一句,如果你的字符串都是相同的长度,或者你可以廉价地将它们填充到固定长度,你不需要 table 指针。您可以改为只从第一个字符串 + 缩放索引的开头计算地址。例如p = .DATA1 + idx*5
在这种情况下,每个字符串的长度为 5 个字节。
lea eax, [.DATA1 + RAX + RAX*4] ; 4+1 = 5
; eax points at the selected 5-byte string buffer
此外,不要使用 .data
作为符号名称。这是一个部分的名称,所以会让人感到困惑。