我正在处理一个问题,我试图在不同的C程序(如)中创建不同的场景
- 数据危害
- 分支机构评估
- 过程调用
这是为了学习流水线技术和出现的不同危险。
因此,我正在编写简单的C程序,并将其反汇编为汇编语言,以查看是否会产生危害。但我不知道如何制造这些危险。你知道我该怎么做吗?以下是我编写的一些简单代码。
我使用编译。
gcc -g -c programName.c -o programName.o
gcc programName.o -o programName
objdump -d programName.o > programName.asm
代码:
#include <stdio.h>
int main()
{
int i = 0;
int size = 5;
int num[5] = {1,2,3,4,5};
int sum=0;
int average = 0;
for(i = 0; i < size; i++)
{
sum += num[i];
}
average=sum/size;
return 0;
}
这是它的组装。
average.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: c7 45 f0 00 00 00 00 movl $0x0,0xfffffffffffffff0(%rbp)
b: c7 45 f4 05 00 00 00 movl $0x5,0xfffffffffffffff4(%rbp)
12: c7 45 d0 01 00 00 00 movl $0x1,0xffffffffffffffd0(%rbp)
19: c7 45 d4 02 00 00 00 movl $0x2,0xffffffffffffffd4(%rbp)
20: c7 45 d8 03 00 00 00 movl $0x3,0xffffffffffffffd8(%rbp)
27: c7 45 dc 04 00 00 00 movl $0x4,0xffffffffffffffdc(%rbp)
2e: c7 45 e0 05 00 00 00 movl $0x5,0xffffffffffffffe0(%rbp)
35: c7 45 f8 00 00 00 00 movl $0x0,0xfffffffffffffff8(%rbp)
3c: c7 45 fc 00 00 00 00 movl $0x0,0xfffffffffffffffc(%rbp)
43: c7 45 f0 00 00 00 00 movl $0x0,0xfffffffffffffff0(%rbp)
4a: eb 10 jmp 5c <main+0x5c>
4c: 8b 45 f0 mov 0xfffffffffffffff0(%rbp),%eax
4f: 48 98 cltq
51: 8b 44 85 d0 mov 0xffffffffffffffd0(%rbp,%rax,4),%eax
55: 01 45 f8 add %eax,0xfffffffffffffff8(%rbp)
58: 83 45 f0 01 addl $0x1,0xfffffffffffffff0(%rbp)
5c: 8b 45 f0 mov 0xfffffffffffffff0(%rbp),%eax
5f: 3b 45 f4 cmp 0xfffffffffffffff4(%rbp),%eax
62: 7c e8 jl 4c <main+0x4c>
64: 8b 55 f8 mov 0xfffffffffffffff8(%rbp),%edx
67: 89 d0 mov %edx,%eax
69: c1 fa 1f sar $0x1f,%edx
6c: f7 7d f4 idivl 0xfffffffffffffff4(%rbp)
6f: 89 45 fc mov %eax,0xfffffffffffffffc(%rbp)
72: b8 00 00 00 00 mov $0x0,%eax
77: c9 leaveq
78: c3 retq
如有任何见解或帮助,不胜感激。谢谢
既然这是家庭作业,我不会给你一个直接的答案,而是一些思考的食物,把你推向正确的方向。
x86是一个糟糕的ISA,用来尝试和理解流水线。一条x86指令可以隐藏两到三个副作用,这使得即使是最简单的管道也很难弄清楚给定指令的执行方式。你确定没有提供RISC ISA来解决这个问题吗?
将循环/危险代码放入函数中,最好将数组的创建随机化。使阵列更长。一个好的编译器基本上会找出答案,否则就会删除你写的大部分代码!出于我不理解的原因,它把你的变量放在了内存中。
一个好的编译器也会做一些事情,比如循环展开,试图隐藏数据隐患并获得更好的代码调度。学习如何克服这一点(或者,如果可以的话,给编译器一个标志,告诉它在允许干扰编译器的情况下不要做这些事情)。
关键字"volatile"非常有助于告诉编译器不要对某些变量进行优化(它"告诉"编译器该值随时可能更改,所以不要聪明地使用它优化代码,也不要将变量保留在寄存器文件中)。
数据危害意味着管道将在等待数据时暂停。通常情况下,指令会被及时绕过,因此不会发生失速。想想哪些类型的指令可能无法绕过,并可能导致数据危险的停滞。这取决于管道,因此为特定处理器暂停的代码可能不会为另一个处理器暂停。现代无序的英特尔处理器非常善于避免这些停滞,编译器也非常善于重新调度代码,因此即使在有序的内核上也不会出现这种情况。