visual-studio - 32 位 MASM 模式与 64 位有何不同?

标签 visual-studio assembly x86 32bit-64bit masm

要使用 MASM 用 32 位汇编语言编写一个完整的程序,可以这样开始,

.686
.model flat,c
.stack 100h
.data
number sdword 5
.code
main proc
mov eax,number
ret
main endp
end main

而在 64 位模式下,代码编写为

.data
number sdword 5
.code
main proc
mov eax,number
ret
main endp
end

设置设置为默认值导致在 64 位模式下组装时发生错误不是因为平台设置为 Win32,而是默认入口点 mainCRTStartup。要解决此问题,必须在高级链接器选项中将其设置为 main

我的问题是,为什么在 32 位模式下不会遇到这样的问题,mainCRTStartup 入口点到底指的是什么?我的第二个问题是,为什么在 64 位模式下我们省略第一条指令行 .686 .model flat,c .stack 100h 我们不必分配堆栈,以及语言类型? 指令.686表示,

Enables assembly of nonprivileged instructions for the Pentium Pro processor. (32-bit MASM only.)

为什么在 64 位模式下不是这样?

最佳答案

32 位 MASM 可以根据指令在 16 位和 32 位可执行文件之间进行选择。构建 64 位代码时情况并非如此,因此相关指令较少。

x86-64 ISA 保证支持 PPro 指令,因此无需启用它们。 (与 SSE/SSE2 相同)。您的代码以 64 位模式运行的事实意味着它们可用,就像 .model flat 中的 movzx 等 386 功能一样。 但是您在 MASM 中使用命令行选项而不是指令来选择

MASM 是否没有针对其他后续扩展的指令,例如 .haswell.bmi2 来帮助您避免意外使用较新的指令,例如 AVX2 vpermpd ymm0, ymm1, 0x01 当你只想使用 AVX1 时?其他一些汇编器确实具有类似的功能,例如 YASM 的 CPU 指令,或者 GNU 汇编器可以让您限制功能。 (默认情况下,GAS 和 YASM/NASM 接受它们所知道的一切。)


x86-64 长模式还强制使用平面内存模型(CS.base = DS.base = ES.base = SS.base)因此无需选择内存模型。非平坦内存分段仅在兼容模式下的 64 位内核下才有可能(如 32 位或 16 位保护模式的用户空间端)。 https://en.wikipedia.org/wiki/X86-64#Operating_modes

此外,MASM .model 也是假设 32 位模式与 16 位模式的代理,这很奇怪。其他汇编程序更正交地将其分开,例如 bits 16/bits 32/bits 64 来设置当前模式。 (但在 NASM 中,这不会改变输出文件格式;这只是让你将 64 位代码放入 32 位目标文件中,除非你正在编写一个 切换的内核,否则你不想这样做 模式。)


对于 .stack,主线程堆栈的最大大小由链接器(使用 /STACK 命令行选项)设置,而不是由汇编器设置。这取代了让汇编器将元数据放入 .obj 文件以供链接器查找或实际工作的机制。 (AFAIK .stack 无论如何只对 16 位可执行文件重要,甚至对 .model flat 也不重要。 您通常不需要 32 位代码中的 256 字节小堆栈。

关于visual-studio - 32 位 MASM 模式与 64 位有何不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65279900/

相关文章:

assembly - 我们何时以及为何签署扩展并使用带有 mul/div 的 cdq?

x86 - "_mm256_cvtepi16_epi32"的倒数是什么

c++ - 为什么 std::tuple 会破坏 C++ 中的小型结构调用约定优化?

C# WPF 组合框可编辑只允许列表中的选项

c++ - 有符号字符的乘法问题

assembly - 将 avr-asm 转换为 arm-gnu 注释的 sed 脚本

c - 如何在 16 位模式下使用 GDB?

c - 内核如何将进程限制在自己的内存池中?

visual-studio - Visual Studio 在突然崩溃时丢失了当前代码

c# - 如何确定是否在面板上执行了右键单击?