小编use*_*622的帖子

为什么BIOS入口点以WBINVD指令开始?

我正在研究我的机器中的BIOS代码(x86_64 Linux,IvyBridge).我使用以下过程来转储BIOS代码:

$ sudo cat /proc/iomem | grep ROM
  000f0000-000fffff : System ROM
$ sudo dd if=/dev/mem of=bios.dump bs=1M count=1
Run Code Online (Sandbox Code Playgroud)

然后我radare2用来读取和反汇编二进制转储:

$ r2 -b 16 bios.dump 
[0000:0000]> s 0xffff0
[f000:fff0]> pd 3
        :   f000:fff0      0f09           wbinvd
        `=< f000:fff2      e927f5         jmp 0xff51c
            f000:fff5      0000           add byte [bx + si], al
Run Code Online (Sandbox Code Playgroud)

我知道x86处理器初始化始终以16位8086环境开始,并且要执行的第一条指令是at f000:fff0,即0xffff0.所以我去那个地方并反汇编代码.

令我惊讶的是WBINVD,第一条指令的功能是使缓存无效,这在处理器上电或复位时似乎无关紧要.我希望第一条指令只是jmp一个较低的内存地址.

为什么WBINVD以前有jmp

我已经搜索了英特尔手册第3卷第9章处理器管理和初始化的相关部分,但它没有提及任何相关内容WBINVD.我也搜索了一些在线资源,但没有找到任何解释.

编辑以获取更多信息:

遵循jmp指令后0xff51c,代码更有趣; 它正在进行自我检查:

[f000:f51c]> pd
            f000:f51c      dbe3 …
Run Code Online (Sandbox Code Playgroud)

boot x86 assembly bios

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

在 IvyBridge 上的指针追逐循环中,来自附近依赖商店的奇怪性能影响。添加额外的负载会加快速度吗?

首先,我在 IvyBridge 上进行了以下设置,我将在注释位置插入测量有效负载代码。前 8 个字节buf存储buf自身的地址,我用它来创建循环携带依赖:

section .bss
align   64
buf:    resb    64

section .text
global _start
_start:
    mov rcx,         1000000000
    mov qword [buf], buf
    mov rax,         buf
loop:
    ; I will insert payload here
    ; as is described below 

    dec rcx
    jne loop

    xor rdi,    rdi
    mov rax,    60
    syscall
Run Code Online (Sandbox Code Playgroud)

情况1:

我插入到有效载荷位置:

mov qword [rax+8],  8
mov rax,            [rax]
Run Code Online (Sandbox Code Playgroud)

perf显示循环为 5.4c/iter。有点理解,因为L1d延迟是4个周期。

案例2:

我颠倒了这两条指令的顺序:

mov rax,            [rax]
mov qword [rax+8],  8
Run Code Online (Sandbox Code Playgroud)

结果突然变成9c/iter。我不明白为什么。因为下一次迭代的第一条指令不依赖于当前迭代的第二条指令,所以这个设置应该和 case 1 没有区别。

我也用IACA工具对这两种情况进行静态分析,但是该工具不可靠,因为两种情况预测的结果都是5.71c/iter,与实验相矛盾。 …

x86 assembly micro-optimization microbenchmark micro-architecture

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

为什么jnz需要在内循环中完成2个循环

我在IvyBridge上.我发现jnz内循环和外循环中的性能行为不一致.

以下简单程序有一个固定大小为16的内部循环:

global _start
_start:
    mov rcx, 100000000
.loop_outer:
    mov rax,    16

.loop_inner:
    dec rax
    jnz .loop_inner

    dec rcx
    jnz .loop_outer

    xor edi, edi
    mov eax, 60
    syscall
Run Code Online (Sandbox Code Playgroud)

perf工具显示外循环运行32c/iter.它表明jnz需要2个周期才能完成.

然后我在Agner的指令表中搜索,条件跳转有1-2"倒数吞吐量",注释"如果没有跳转就快".

在这一点上,我开始相信上述行为是以某种方式预期的.但为什么jnz在外循环中只需要1个循环来完成?

如果我.loop_inner完全删除部件,外部循环运行1c/iter.行为看起来不一致.

我在这里缺少什么?

编辑以获取更多信息:

perf上述程序的结果带命令:

perf stat -ecycles,branches,branch-misses,lsd.uops,uops_issued.any -r4 ./a.out
Run Code Online (Sandbox Code Playgroud)

是:

 3,215,921,579      cycles                                                        ( +-  0.11% )  (79.83%)
 1,701,361,270      branches                                                      ( +-  0.02% )  (80.05%)
        19,212      branch-misses             #    0.00% of all branches          ( +- 17.72% )  (80.09%)
        31,052      lsd.uops                                                      ( …
Run Code Online (Sandbox Code Playgroud)

x86 micro-optimization microbenchmark micro-architecture

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