相关疑难解决方法(0)

"rep ret"是什么意思?

我在Visual Studio 2008上测试了一些代码并注意到了security_cookie.我能理解它的重点,但我不明白这条指令的目的是什么.

    rep ret /* REP to avoid AMD branch prediction penalty */
Run Code Online (Sandbox Code Playgroud)

当然我可以理解评论:)但是这个前缀exaclty在上下文中做了ret什么,如果ecx是!= 0 会发生什么?显然,ecx当我调试它时,忽略循环计数,这是预期的.

我发现这里的代码在这里(由编译器注入安全性):

void __declspec(naked) __fastcall __security_check_cookie(UINT_PTR cookie)
{
    /* x86 version written in asm to preserve all regs */
    __asm {
        cmp ecx, __security_cookie
        jne failure
        rep ret /* REP to avoid AMD branch prediction penalty */
failure:
        jmp __report_gsfailure
    }
}
Run Code Online (Sandbox Code Playgroud)

x86 assembly

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

Haswell/Skylake的部分寄存器究竟如何表现?写AL似乎对RAX有假依赖,而AH是不一致的

此循环在英特尔Conroe/Merom上每3个周期运行一次,imul按预期方式在吞吐量方面存在瓶颈.但是在Haswell/Skylake上,它每11个循环运行一次,显然是因为setnz al它依赖于最后一个循环imul.

; synthetic micro-benchmark to test partial-register renaming
    mov     ecx, 1000000000
.loop:                 ; do{
    imul    eax, eax     ; a dep chain with high latency but also high throughput
    imul    eax, eax
    imul    eax, eax

    dec     ecx          ; set ZF, independent of old ZF.  (Use sub ecx,1 on Silvermont/KNL or P4)
    setnz   al           ; ****** Does this depend on RAX as well as ZF?
    movzx   eax, al
    jnz  .loop         ; }while(ecx);
Run Code Online (Sandbox Code Playgroud)

如果setnz al …

x86 assembly intel cpu-architecture micro-optimization

30
推荐指数
2
解决办法
1537
查看次数

在现代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
查看次数

32 字节对齐例程不适合 uops 缓存

KbL i7-8550U

我正在研究 uops-cache 的行为并遇到了关于它的误解。

如英特尔优化手册2.5.2.2(我的)中所述:

解码的 ICache 由 32 组组成。每组包含八种方式。 每路最多可容纳六个微操作。

——

Way 中的所有微操作表示在代码中静态连续的指令,并且它们的 EIP 位于相同的对齐 32 字节区域内。

——

最多三种方式可以专用于相同的 32 字节对齐块,从而允许在原始 IA 程序的每个 32 字节区域中缓存总共 18 个微操作。

——

无条件分支是 Way 中的最后一个微操作。


情况1:

考虑以下例程:

uop.h

void inhibit_uops_cache(size_t);
Run Code Online (Sandbox Code Playgroud)

uop.S

align 32
inhibit_uops_cache:
    mov edx, esi
    mov edx, esi
    mov edx, esi
    mov edx, esi
    mov edx, esi
    mov edx, esi
    jmp decrement_jmp_tgt
decrement_jmp_tgt:
    dec rdi
    ja inhibit_uops_cache ;ja is intentional to avoid Macro-fusion
    ret
Run Code Online (Sandbox Code Playgroud)

为了确保例程的代码实际上是 32 字节对齐的,这里是 asm …

performance x86 assembly intel cpu-architecture

7
推荐指数
1
解决办法
483
查看次数

x86多字节NOP和指令前缀

回想一下,x86体系结构定义0x0F 0x1F [mod R/M]为多字节NOP。

现在,我看一个8字节NOP的特殊情况:

0x0F 0x1F 0x84 0x__ 0x__ 0x__ 0x__ 0x__
Run Code Online (Sandbox Code Playgroud)

最后5个字节具有任意值。

第三个字节[mod R/M]拆分得到:

现代

  • mod = 10b:参数为reg1+ DWORD大小的位移
  • reg2 = 000b:(我们不在乎)
  • reg1 = 100b:表示参数改为SIB字节+ DWORD大小的位移。

现在,举一个具体的例子

0x0F 0x1F 0x84 0x12 0x34 0x56 0x78 0x9A
Run Code Online (Sandbox Code Playgroud)

我有

  • SIB = 0x12
  • displacement = 0x9A785634:DWORD

现在,我添加0x66指令前缀以指示位移应为WORD而不是DWORD:

0x66 0x0F 0x1F 0x84 0x12 0x34 0x56 0x78 0x9A
Run Code Online (Sandbox Code Playgroud)

我希望0x78 0x9A被“切断”并被视为新的指示。但是,当编译它并objdump在生成的可执行文件上运行时,它仍然使用所有4个字节(一个DWORD)作为位移。

在这种情况下,我是否误解了“位移”的含义?还是0x66前缀对多字节NOP指令没有任何影响?

x86 prefix nop

5
推荐指数
1
解决办法
2513
查看次数

MOV Moffs32在64位模式下地址的符号扩展还是零扩展?

让我们MOV EAX,[0xFFFFFFFF]64位模式将指令编码为67A1FFFFFFFF(有效地址大小由67前缀从默认的64位切换为32位)。

英特尔指令参考手册(从2015年12月起,文档订购号:325383-057US)在第Vol。2A 2-11说:

2.2.1.3
64位模式下的位移寻址使用现有的32位ModR / M和SIB编码。ModR / M和SIB大小不变。它们保留为8位或32位,并被符号扩展为64位。

这表明应该对32bit位移进行符号扩展,但是我不确定这是否也涉及特殊的moffs寻址模式。英特尔在下一页上说:

2.2.1.6 RIP相对寻址

RIP相对寻址是通过64位模式而不是64位地址大小启用的。地址大小前缀的使用不会禁用RIP相对寻址。地址大小前缀的作用是将计算的有效地址截断并将其零扩展为32位。

这表明在相对寻址模式下,将disp32符号扩展到64位,再添加到RIP,然后截断并进行零扩展。但是,我不确定同一规则是否适用于绝对寻址模式,MOV moffs操作就是这种情况。

从A)FFFFFFFFFFFFFFFF或B)00000000FFFFFFFF将EAX加载到哪个地址?

64-bit x86 assembly x86-64 memory-address

5
推荐指数
1
解决办法
848
查看次数

为什么 x86 16 位寻址模式没有比例因子,而 32 位版本有比例因子?

我试图找出 x86 16 位寻址模式(MASM 程序集)中不存在比例因子的原因。而32位和64位寻址模式都有比例因子。这背后是否有实际原因或者不需要它?如果您能解释一下,我将不胜感激。

可以组合不同组件来创建有效地址的所有可能方式:

Image of all possible ways different components can be combined to create an effective address

16 位和 32 位寻址模式之间的差异

Differences between 16- and 32-bit addressing modes

x86 assembly addressing-mode x86-16

5
推荐指数
1
解决办法
1158
查看次数

与其他宽度不同,为什么短(16 位)变量将值移动到寄存器并存储该值?

int main()
{
00211000  push        ebp  
00211001  mov         ebp,esp  
00211003  sub         esp,10h  
    char charVar1;
    short shortVar1;
    int intVar1;
    long longVar1;
    
    charVar1 = 11;
00211006  mov         byte ptr [charVar1],0Bh  

    shortVar1 = 11;
0021100A  mov         eax,0Bh  
0021100F  mov         word ptr [shortVar1],ax  

    intVar1 = 11;
00211013  mov         dword ptr [intVar1],0Bh 
 
    longVar1 = 11;
0021101A  mov         dword ptr [longVar1],0Bh  
}
Run Code Online (Sandbox Code Playgroud)

其他数据类型不通过寄存器,但只有短类型通过寄存器。怎么了?

c x86 assembly cpu-architecture micro-optimization

5
推荐指数
1
解决办法
158
查看次数

如何以 gcc AT&T 风格将内存中某个地址的值复制到寄存器

我想使用 AT&T 风格的汇编将内存中某个地址的值复制到寄存器。我知道这应该不难,我认为在英特尔风格中它是这样的:

mov rdi, [0xdeadbeef]
Run Code Online (Sandbox Code Playgroud)

但我对 AT&T 风格(或一般的组装)了解不多。我搜索了它,但我得到的所有例子mov都不包括这个。

那么谁能告诉我该指令是什么样的?

另外,在哪里可以找到 AT&T 风格的 x86_64 汇编指令的完整列表?

assembly x86-64 att

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

NASM %rep 部分中的标签

我有%rep一个预处理器指令,它创建一个预处理器循环。我想在其中声明标签,可能带有一些串联,但我无法获得正确的语法。

%assign i 0 
%rep    64 
   label_%i: ;this, of course, doesn't work
      inc rax    
%assign i i+1 
%endrep
Run Code Online (Sandbox Code Playgroud)

那么如何强制 NASM 预处理器label_i为每次“迭代”生成呢?

assembly preprocessor nasm

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

x86 汇编 16 位与 8 位立即操作数编码

我正在编写自己的汇编程序并尝试对 ADC 指令进行编码,我对立即值有疑问,尤其是在将 8 位值添加到 AX 寄存器时。

添加 16 位值时:adc ax, 0xff33被编码为15 33 ff正确的。但是如果adc ax, 0x33被编码为会重要15 33 00吗?

Nasm 将83 d0 33其编码为显然是正确的,但我的方法也正确吗?

x86 assembly machine-code opcode instruction-encoding

3
推荐指数
1
解决办法
1327
查看次数

将1个字节的立即值添加到2个字节的内存位置

本页add说明文档说明如下:

在此输入图像描述

请注意我突出显示的两条指令.

我在NASM中尝试了以下代码(符合第一个突出显示的指令):

add WORD [myvar], BYTE 0xA5
Run Code Online (Sandbox Code Playgroud)

但是我收到以下错误:

警告:有符号字节值超出边界

我究竟做错了什么?

x86 assembly nasm

2
推荐指数
1
解决办法
978
查看次数

rbp不允许作为SIB基础?

我对x86-64二进制编码很新.我正在尝试修复一些旧的"汇编程序"代码.

无论如何,我正在尝试做这样的事情(英特尔语法):

mov    [rbp+rcx], al
Run Code Online (Sandbox Code Playgroud)

汇编程序目前正在生成:

88 04 0D
Run Code Online (Sandbox Code Playgroud)

但这似乎不是一个有效的指示.如果我将SIB字节中的基数更改rbp为其他寄存器,则可以正常工作.另一种使其工作的方法是添加一个零字节的位移(88 44 0D 00).这似乎与其他类似的操作码一起发生.

为什么我不能rbp在那里使用mod=00

x86 assembly x86-64 machine-code addressing-mode

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