相关疑难解决方法(0)

为什么32位寄存器上的x86-64指令归零整个64位寄存器的上半部分?

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汇编的怪癖).

x86 assembly x86-64 cpu-registers zero-extension

97
推荐指数
3
解决办法
2万
查看次数

在Linux中编译/运行汇编程序?

我是Linux的新手(Ubuntu 10.04),也是汇编程序的新手.我正在学习一些教程,但我找不到任何特定于Linux的内容.所以,我的问题是,什么是编译/运行汇编程序的好包,以及为该程序包编译/运行的命令行命令是什么?

linux ubuntu x86 assembly

54
推荐指数
5
解决办法
11万
查看次数

x86-64 Linux中不再允许32位绝对地址?

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位绝对地址?

linux gcc x86-64 linker-errors relocation

21
推荐指数
1
解决办法
5787
查看次数

在现代x86上有哪些方法可以有效地扩展指令长度?

想象一下,您希望将一系列x86汇编指令与某些边界对齐.例如,您可能希望将循环对齐到16或32字节的边界,或者将指令打包以使它们有效地放置在uop缓存中或其他任何位置.

实现这一目标的最简单方法是单字节NOP指令,紧接着是多字节NOP.虽然后者通常效率更高,但这两种方法都不是免费的:NOP使用前端执行资源,并且还计入现代x86上的4宽1重命名限制.

另一个选择是以某种方式延长一些指令以获得所需的对齐.如果这样做没有引入新的停顿,它似乎比NOP方法更好.如何在最近的x86 CPU上有效地延长指令?

在理想的世界中,延长技术同时是:

  • 适用于大多数说明
  • 能够通过可变数量延长指令
  • 不会停止或以其他方式减慢解码器的速度
  • 在uop缓存中有效表示

有一种方法不可能同时满足所有上述要点,因此很好的答案可能会解决各种权衡问题.


1 AMD Ryzen的限制为5或6.

optimization performance x86 assembly micro-optimization

20
推荐指数
1
解决办法
683
查看次数

如何将函数或标签的地址加载到寄存器中

我正在尝试将“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 编译不能解决问题,只会给我同样的错误。

assembly gcc x86-64 att addressing-mode

10
推荐指数
1
解决办法
5302
查看次数

从64位地址加载到rax以外的其他寄存器

在x64上,可以通过以下方式从64位绝对地址加载(即,取消引用64位立即数)

movabs addr64, %rax
Run Code Online (Sandbox Code Playgroud)

但是,当目标寄存器不是rax汇编程序给出错误消息时operand size mismatch for movabs.我错过了什么?

assembly x86-64

9
推荐指数
1
解决办法
4894
查看次数

x86-64 AT&T指令movq和movabsq有什么区别?

看完这个堆栈溢出的答案,而这个文件,我还是不明白之间的差别movqmovabsq.

我目前的理解是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

我错过了什么?

assembly x86-64 att

8
推荐指数
1
解决办法
513
查看次数

在Windows上编译Nasm程序时未定义的对"WinMain"的引用(MinGW)

我想在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)

我错过了什么?如何修复此错误?

windows assembly mingw nasm

6
推荐指数
1
解决办法
611
查看次数

错误:`movq'的操作数大小不匹配

我正在尝试编译以下程序集......

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)

assembly x86-64

4
推荐指数
1
解决办法
4640
查看次数

在x86汇编中将64位常量移动到内存

我正在使用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)

64-bit x86 assembly x86-64 nasm

4
推荐指数
1
解决办法
2315
查看次数