32位英特尔处理器的装配与64位版本有何不同?

时间:2016-06-23 14:43:26

标签: assembly

我已经开始学习汇编,但对本书的第一句话感到担忧:

  

在本书中,我们主要关注Pentium等Intel 32位处理器的汇编语言。

32位到64位的程序集有何不同? 值得学习两者还是通过学习32位我可以使用64位一个好吗?

5 个答案:

答案 0 :(得分:4)

64位模式引入了一些架构变化 可以在英特尔的Manual 1的第3.2.1章

中找到不完整的列表
  

•地址空间 - 在IA-32处理器上以64位模式运行的任务或程序可以寻址线性地址   最多2 ^ 64字节的空间(根据第3.3.7.1节中描述的规范寻址要求)和   物理地址空间最多为2 ^ 46字节。软件可以查询CPUID以获取支持的物理地址大小   由处理器。

     

[以前只能处理最多4个GiB(当然不是全部可用于RAM),而不是当前限制为64 TiB]

     

•基本程序执行寄存器 - 可用的通用寄存器(GPR)的数量为16。   GPR是64位宽,它们支持字节,字,双字和四字整数的操作。   访问字节寄存器均匀地完成最低8位。指令指针寄存器变为64位。   EFLAGS寄存器扩展到64位宽,称为RFLAGS寄存器。高32位   RFLAGS保留。 RFLAGS的低32位与EFLAGS相同。见图3-2。

     

[x86有8个通用寄存器:EAX,EBX,EBX,EDX,ESI,EDI,EBP,EDI。每一个32位。现在有16个GP寄存器,64位:RAX,RBX,RCX,RDX,RSI,RDI,RBP,RSP,R8-R15。这些寄存器的低32位是旧的32位寄存器。其他寄存器扩展并可以寻址,如BPL]

     

•XMM寄存器 - SIMD操作有16个XMM数据寄存器。请参见第10.2节“SSE编程”   环境,“有关这些寄存器的更多信息。

     

[以前只有8个XMM0-XMM7 128位SIMD寄存器。 YMM与AVX相同]

     

•堆栈 - 堆栈指针大小为64位。堆栈大小不受SS描述符中的位控制(因为它在   非64位模式)指针大小也不能被指令前缀覆盖。

     

[正如预期的那样,堆栈指针是RSP]

     

•控制寄存器 - 控制寄存器扩展为64位。一个新的控制寄存器(任务优先级寄存器:CR8   或TPR)已被添加。请参阅本卷中的第2章“英特尔®64和IA-32架构”   •调试寄存器 - 调试寄存器扩展为64位。请参见第17章“调试,分支配置文件,TSC和   “服务质量”,“英特尔®64和IA-32架构软件开发人员手册,第3A卷。

     

[这适用于64位指针]

这主要是一个介绍性列表,还有其他变化:

  • 根据经验,现在拥有地址的所有内容都是64位。
  • 在64位模式(长按模式)中禁用分段,仅 FS GS 选择的描述符基数和限制。
  • 由于引入了 REX 前缀,某些指令(如inc ax的一个字节形式不再可编码(即可用)。
  • 32位寄存器的算术运算清除了整个64位寄存器的高32位(即mov eax, 1清除了 RAX 的上部DWORD。)
  • 在操作码级别,大多数立即操作数仍然是32位但是符号扩展。像add ebx, 0123456789abcdefh这样的说明不可编码。
  • 物理地址必须是规范的,以避免混叠,即符号扩展为64位。
  • 新的寻址模式可用:RIP相对,即与当前指令地址的偏移量可用于访问数据。这有助于位置独立代码。

所有这些仍然是初步的,如果您感兴趣,可以谷歌搜索相关条款或查看Intel manuals

然而,当从32位切换到64位时,最重要的是使用ABI的更改,您需要调整对运行时库过程的调用。

作为变化的一个例子:
参数现在在寄存器(第一个四分之一)上传递,堆栈必须对齐,向量寄存器用于浮点,堆栈上有红色区/转储区。

每个平台都有自己的ABI,例如,您可以检查SysV ABI的完整列表。

答案 1 :(得分:1)

信不信由你,“Intel x86”处理器架构一直回到(koff,koff ...... wheeze ......“今天这些KIDS”......) { {1}} (群众的计算器控制器......)。从那以后,Intel 8008 (首先开始制作比尔盖茨富豪的芯片)

从那时起每一个处理器化身...... Intel 8080 ...... 8086 ......英特尔尽职尽责地试图通过一个相当增加的(!)数字来“容纳过去” “向后兼容的'处理器模式'。”

当然,这些“模式”中的每一种都是为了保护现有软件免受软件编写时尚未存在的潜在副作用的影响。

答案 2 :(得分:1)

除了x64处理器可以按原样执行32位x86之外,x86指令集大多与x64指令集兼容。 add ebx, eax在x64中仍然有效。但是有一些不同之处。例如,push es无效,指针为64位:mov dword ptr[esi], eax有效,但可能无效,因为您可能会截断rsi中的指针。

这意味着学习32位x86或64位x64之间没有太大区别。你也可以。如果你有选择的话,我的意见就是学习x64:这就像学习两种方法一样。

答案 3 :(得分:0)

ABI不同,但实际的指令集非常相似。请参阅quick guide to what's different in x86-64 链接的tag wiki

在现代操作系统中,相同的系统调用API在32位和64位中可用,但ABI存在差异(例如var d = new Date(); var $checkTime = d.getHours(); jQuery(function() { if ($checkTime >= 10) { jQuery("#date").datepicker( { minDate: +2, maxDate: '+6M', dateFormat: 'dd MM yy', beforeShowDay: checkBadDates }); } else { jQuery("#date").datepicker( { minDate: +1, maxDate: '+6M', dateFormat: 'dd MM yy', beforeShowDay: checkBadDates }); } }); var $myBadDates = new Array({{ settings.bad_delivery_date }}); function checkBadDates(mydate){ var $return=true; var $returnclass ="available"; var $checkdate = $.datepicker.formatDate('dd MM yy', mydate); for(var i = 0; i < $myBadDates.length; i++) { if($myBadDates[i] == $checkdate) { $return = false; $returnclass= "unavailable"; } } return [$return,$returnclass]; } int 0x80)。

但是通过学习32位代码,你不会浪费时间学习只对DOS程序有用的DOS系统调用。

IDK如果立即学习64位代码更容易或不容易。你经常可以编写不必真正使用堆栈的函数;可能只是syscall / push来保存/恢复某些内容。在某些方面,这是一件好事。你可以推迟学习如何使用堆栈,同时绕过其他基础知识,比如让你的分支逻辑正确。

32位ABI基本上迫使你立即学习堆栈布局,因为args总是在堆栈上传递。

如果你想编写真正高效的64位代码(当32位操作数大小足够时,它不会在REX前缀上浪费指令字节),那还有一件事需要考虑。但是,当你正在学习时,只需确定正确性就可以了。并且您偶尔需要担心将32位signed int符号扩展到64位以用作寻址模式中的偏移量。

答案 4 :(得分:0)

(作为第二个答案,是的......)我会喜欢插入这个交换中的实用观察“直接汇编语言不再使用太多了。”当它是,最有可能在更高级语言(“C ...”)程序中找到asm{ ...}个部分。

...而且,很多时候这些天,它可能是不必要的,因为编译器通常能够生成对象代码,好或更好(可能,明显更好......)你可以用手做什么。当然,情况并非总是如此。

一个很好的例子就是Linux内核源代码的/arch子树。除了所谓的“trampoline”部分,某些体系结构在启动时使用这些部分,从字面上看,“还没有其他任何东西存在”,大多数特定于体系结构的汇编代码都包含非常有针对性的子例程。 / i>其中一些不仅是“架构级特定的”(例如“x86”),,而是制造商特定的(“AMD ......”),但是,让记录清楚地表明这些事情是例外,而不是规则。

是的,我同意你需要知道各种CPU架构是如何“在裸机上”运行的,但我可以指望双手的手指我想的次数我可以比编译器做得更好。 (不包括那些我在经过高度修改的大型机操作系统上为每日面包做工作的那些年,这些操作系统主要由汇编程序构建。 Ick ...)