在x86-64 Tour of Intel Manuals中,我读到了
也许最令人惊讶的事实是,诸如
MOV EAX, EBX自动将指令的高32位归零的指令RAX.
同一来源引用的英特尔文档(3.4.1.1 64位手动基本架构中的通用寄存器)告诉我们:
- 64位操作数在目标通用寄存器中生成64位结果.
- 32位操作数生成32位结果,在目标通用寄存器中零扩展为64位结果.
- 8位和16位操作数生成8位或16位结果.目标通用寄存器的高56位或48位(分别)不会被操作修改.如果8位或16位操作的结果用于64位地址计算,则将寄存器显式符号扩展为完整的64位.
在x86-32和x86-64汇编中,16位指令如
mov ax, bx
Run Code Online (Sandbox Code Playgroud)
不要表现出这种"奇怪"的行为,即eax的上层词被归零.
因此:引入这种行为的原因是什么?乍一看似乎不合逻辑(但原因可能是我习惯了x86-32汇编的怪癖).
我是Linux的新手(Ubuntu 10.04),也是汇编程序的新手.我正在学习一些教程,但我找不到任何特定于Linux的内容.所以,我的问题是,什么是编译/运行汇编程序的好包,以及为该程序包编译/运行的命令行命令是什么?
64位Linux默认使用小内存模型,它将所有代码和静态数据置于2GB地址限制之下.这可确保您可以使用32位绝对地址.较旧版本的gcc使用静态数组的32位绝对地址,以便为相对地址计算保存额外的指令.但是,这不再有效.如果我尝试在汇编中创建一个32位的绝对地址,我会收到链接器错误:"在创建共享对象时,不能使用".data"重定位R_X86_64_32S;使用-fPIC重新编译".当然,此错误消息具有误导性,因为我没有创建共享对象,-fPIC也没有帮助.到目前为止我发现的是:gcc版本4.8.5对静态数组使用32位绝对地址,gcc版本6.3.0不使用.版本5可能也没有.binutils 2.24中的链接器允许32位绝对地址,而2.28则不允许.
这种变化的后果是必须重新编译旧库并破坏传统汇编代码.
现在我想问一下:这个改变是什么时候做的?它在某处记录了吗?是否有一个链接器选项,使其接受32位绝对地址?
想象一下,您希望将一系列x86汇编指令与某些边界对齐.例如,您可能希望将循环对齐到16或32字节的边界,或者将指令打包以使它们有效地放置在uop缓存中或其他任何位置.
实现这一目标的最简单方法是单字节NOP指令,紧接着是多字节NOP.虽然后者通常效率更高,但这两种方法都不是免费的:NOP使用前端执行资源,并且还计入现代x86上的4宽1重命名限制.
另一个选择是以某种方式延长一些指令以获得所需的对齐.如果这样做没有引入新的停顿,它似乎比NOP方法更好.如何在最近的x86 CPU上有效地延长指令?
在理想的世界中,延长技术同时是:
有一种方法不可能同时满足所有上述要点,因此很好的答案可能会解决各种权衡问题.
1 AMD Ryzen的限制为5或6.
我正在尝试将“main”的地址加载到 GNU 汇编器中的寄存器 (R10) 中。我没办法。在这里,我有什么和我收到的错误消息。
main:
lea main, %r10
Run Code Online (Sandbox Code Playgroud)
我还尝试了以下语法(这次使用 mov)
main:
movq $main, %r10
Run Code Online (Sandbox Code Playgroud)
使用以上两种方法,我都会收到以下错误:
/usr/bin/ld: /tmp/ccxZ8pWr.o: relocation R_X86_64_32S against symbol `main' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
使用 -fPIC 编译不能解决问题,只会给我同样的错误。
在x64上,可以通过以下方式从64位绝对地址加载(即,取消引用64位立即数)
movabs addr64, %rax
Run Code Online (Sandbox Code Playgroud)
但是,当目标寄存器不是rax汇编程序给出错误消息时operand size mismatch for movabs.我错过了什么?
看完这个堆栈溢出的答案,而这个文件,我还是不明白之间的差别movq和movabsq.
我目前的理解是movabsq,第一个操作数是一个64位立即数操作数,而movq符号扩展一个32位立即数操作数.从上面引用的第二个文件:
将立即数据移动到64位寄存器可以通过
movq指令进行,该指令将签署扩展32位立即值,或者movabsq在需要完整的64位立即数时使用指令.
在第一篇参考文献中,彼得说:
有趣的实验:
movq $0xFFFFFFFF, %rax可能不可编码,因为它不能用符号扩展的32位立即数表示,并且需要imm64编码或%eax目标编码.
但是,当我组装/运行它时似乎工作正常:
.section .rodata
str:
.string "0x%lx\n"
.text
.globl main
main:
pushq %rbp
movq %rsp, %rbp
movl $str, %edi
movq $0xFFFFFFFF, %rsi
xorl %eax, %eax
call printf
xorl %eax, %eax
popq %rbp
ret
Run Code Online (Sandbox Code Playgroud)
$ clang file.s -o file && ./file
打印0xffffffff.(这适用于较大的值,例如,如果你输入一些额外的"F").movabsq生成相同的输出.
Clang是在推断我想要的吗?如果是,是否有仍然是受益movabsq过度movq?
我错过了什么?
我想在Windows上编译Hello World NASM示例.
我已将上面的代码粘贴到一个main.asm文件中,并使用以下命令将其编译为obj文件:
nasm -fwin32 .\main.asm -o main.obj
Run Code Online (Sandbox Code Playgroud)
之后我想将这个obj文件编译成一个exe,如下所示:
g++ .\main.obj -o main.exe -m32
Run Code Online (Sandbox Code Playgroud)
但我得到这个错误:
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/lib/../lib/libmingw32.a(lib32_libmingw32_a-crt0_c.o):crt0_c.c:(.text.startup+0x39): undefined reference to `WinMain@16'
Run Code Online (Sandbox Code Playgroud)
我错过了什么?如何修复此错误?
我正在尝试编译以下程序集......
movq $0x3534373536383235, 0x000000000055638f8
movq $0x55638f8, %rdi
retq
Run Code Online (Sandbox Code Playgroud)
在第一线引发错误Error: operand size mismatch for 'movq'
这对我来说没有意义,因为它们都是8字节数字.
我做了一点研究movabsq并被推荐,就像这样......
movabsq $0x3534373536383235, 0x000000000055638f8
movq $0x55638f8, %rdi
retq
Run Code Online (Sandbox Code Playgroud)
但这会引发错误: Error: operand size mismatch for 'movabs'
我错过了什么?
这是我的mac的整个错误
level3.s:1:27: error: invalid operand for instruction
movq $0x3534373536383235, 0x000000000055638f8
^~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud) 我正在使用Intel x64汇编,NASM编译器,尝试将"0x4000000000000000"常量移动到内存,在ieee 754标准double中应该等于2.0.
我正在使用的代码是:
%define two 0x4000000000000000
section .text
foo:
push rbp
mov rbp, rsp
mov QWORD [rdi], two
pop rbp
ret
Run Code Online (Sandbox Code Playgroud)
编译此抛出
警告:签名dword立即超出界限.
当我用C++打印值时,它显示"0"而不是"2".
我已经找到了获得正确价值的方法,即:
mov r9, 0x4000000000000000
mov [rdi], r9
Run Code Online (Sandbox Code Playgroud)
但我想知道是否有办法在不使用寄存器的情况下实现这一目标.
顺便说一句,我用这个脚本编译代码:
#!/bin/bash
nasm -f elf64 -g -F dwarf vvp_asm.asm -o vvp_asm.o
g++ -c -m64 -std=c++11 main.cpp -o main.o
g++ -o main -m64 vvp_asm.o main.o
Run Code Online (Sandbox Code Playgroud) assembly ×9
x86-64 ×7
x86 ×4
att ×2
gcc ×2
linux ×2
nasm ×2
64-bit ×1
mingw ×1
optimization ×1
performance ×1
relocation ×1
ubuntu ×1
windows ×1