AMD和Intel程序员的模型兼容性

时间:2019-01-26 13:59:26

标签: x86 intel amd

我已经阅读了《英特尔软件开发指南》(第1-3卷)。

如果不做类似的阅读《 AMD编程指南》(第1-5卷),我想知道英特尔和AMD编程模型的哪些方面是相同的。

当然,即使在一系列处理器中,也将存在特定于模型的寄存器,并支持各种扩展和功能。

但是,英特尔确实对一些简单的东西做了一般性的陈述,总的来说,我不确定它们是否适用于AMD。例如:

  • 缓存行大小
  • 每种内存类型的内存顺序保证
  • 每种内存类型的原子读写保证
  • ect。

请注意,我并不是专门询问这些示例。我要问的是,从程序员的角度来看,就编写功能上等效的代码而言,AMD和Intel编程模型是否等效?

(这里只涉及AMD64和Intel 64架构)

1 个答案:

答案 0 :(得分:1)

通常不是相当,编程模型并不总是完全等效。如果您想100%确定,则需要检查两组文档。

https://en.wikipedia.org/wiki/X86-64#Differences_between_AMD64_and_Intel_64

例如bsf / bsr:Intel文档说他们未定义目的地,AMD说他们将其保留为零。但实际上,英特尔这样做是因为它对输出寄存器具有微体系结构依赖性。 This false-dependency infected lzcnt/tzcnt as well until Skylake, and popcnt still,在Intel而非AMD。但是,直到英特尔将它们写在纸上,让他们保持使其硬件表现为这种方式之前,编译器才不会利用它,我们也许也不应该手工。 (尽管维基百科似乎在英特尔上说,对于英特尔上的bsf eax, ecx,目的地的高32位可能是未定义的,而不是为零。因此,严格来说,这并不总是像编写EAX。)


这对于内核代码尤其重要,特权指令的行为可能会有更细微的差异。我认为TLB无效语义大多匹配,例如可以确保在将无效条目更改为有效后都不需要使TLB无效。因此,x86不允许“负缓存”,因此想要这样做的实现将必须监听页表存储以保持一致性。

其中某些可能是无意的,例如Intel和AMD都具有针对x86-64非规范地址的sysret的不同错误,因此在ptrace系统调用可能会修改保存的RIP之后使用它并不安全。切换到用户堆栈后,在内核模式下可能会发生GP错误,将内核的控制权从可以修改堆栈内存的同一进程移交给另一个用户空间线程。 (https://blog.xenproject.org/2012/06/13/the-intel-sysret-privilege-escalation/)这就是为什么Linux总是使用iret的原因,除了通常情况下的快速路径外,在这种情况下,已保存的寄存器是已知清除的。 comments in entry_64.S in the kernel source summarize a bit


在AMD上,未对齐的缓存加载/存储的原子性保证较弱:由于AMD,在x86-64上小至8字节的边界可能很重要。 Why is integer assignment on a naturally aligned variable atomic on x86?涵盖了其中的常见子集。


缓存行大小从未正式标准化。实际上,Intel和AMD CPU使用64字节的行,并且可以在运行时使用CPUID在两者上以相同的方式对其进行查询。


AFAIK,至少对于WB,内存顺序规则是相同的,并且可能对于其他类型(包括WC和与LFENCE / SFENCE / MFENCE与lock add的交互)也是相同的。尽管lockxchg的意图与mfence不同,但英特尔并没有明确记录。但是您要问的是编程模型本身,而不仅仅是文档在纸上说了什么。参见Does lock xchg have the same behavior as mfence?What is the difference in logic and performance between LOCK XCHG and MOV+MFENCE?

关于AMD的IDK,但是NT WC负载可能在Intel上用lock add / xchg重新排序(但我认为他们不应该在MFENCE上使用,这就是为什么Intel ucode更新必须像LFENCE的其他效果一样,在Skylake上加强MFENCE以阻止OoO执行程序,以防止以后的负载完全进入管道。)@ Bee在第一个链接上的回答提到了这一点,请参见the bottom of this。在测试真实的硬件时,总是很难说出什么是将来可以保证的行为,什么仅仅是实现细节,而这正是手册的来源。