我正在研究我的机器中的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) 首先,我在 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)
我插入到有效载荷位置:
mov qword [rax+8], 8
mov rax, [rax]
Run Code Online (Sandbox Code Playgroud)
perf显示循环为 5.4c/iter。有点理解,因为L1d延迟是4个周期。
我颠倒了这两条指令的顺序:
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
我在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)