LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1306|回复: 14

AMD64学习心得

[复制链接]
发表于 2005-5-22 07:17:41 | 显示全部楼层 |阅读模式
从版主提供的地址down到了AMD64的程序员手册,很是兴奋的看了起来。现在写一点学习心得。
这份手册一共有5个volume,分别是Application Programming,System Programming, General-Purpose Instruction Reference, 128-Bit Media Instructions, 64Bit Media and x87 Floating Point Instruction。加起来有几千页的样子。但如果对多媒体和浮点运算没有兴奋的话,最后两卷和第一卷的后半部分都没必要看。第三卷是指令参考,如果以前学过汇编的也没必要看了,指令都差不多,需要的时候翻一下就可以了。
现在我只看了第一卷的前两章,大概了解了一些AMD64 CPU的新特点。AMD64很可能是新一代CPU的标准,就像当年的80386一样。因为微软公司不想再开发一套win64,所以要求intel也遵循这个标准。
首先看看运行模式,AMD64支持long mode和legacy mode两种运行模式。在legacy mode下,amd64相点于一个快速的80386 CPU,原有的所有32位程序和16位程序无需重新编译就可以达个模式下运行。long mode是AMD64全新的特点,long mode下又可分为两个方式,64-bit mode和compatibility mode。其中compatibility mode也就相当于80386的v86 mode,用于在64位操作系统下运行32位程序。当然,如果你喜欢还可以在compatibility mode下进入v86 mode,因为是完全兼容嘛。
64-bit mode的重点。令我惊奇的是这份手册还不厌其烦的介绍80386的protected mode。不过我就不讲这些了,只介绍64-bit mode下的情况。
新的AMD64 CPU扩展了原有的几个通用寄存器至64位,把原有寄存器名开头的"E"变成了"R",例如EAX变成RAX,EFLAGS变成RFALGS,总之所有E打头的换成R就是。另外新加入了8个64位通用寄存器R8-R15。继承了MMX指令集的8个64位多媒体/浮点运算寄存器MMX0-MMX7/FPR0-FPR7,XMM指令集的8个128位多媒体寄存器XMM0-XMM7,又新加了8个128位多媒体寄存器XMM8-XMM15。几个段寄存器不变。
最让人兴奋的是,64-bit mode下使用了64位平展地址,80386下最让人头痛的段选择子+段内偏移的方式终于可以彻底告别。而段寄存器也几乎没有什么作用了,但在某下特别应用下可以通过设置段寄存器在64-bit mode使用32位地址。“有效地址”这个概念也再没必要存在,虚拟地址就是有效地址。经过paging之后,64位的虚拟地址变换成为52位的物理地址,只支持52位物理可能是为了节省页表的空间,大概AMD认为不可能有人会用到超过2^52的内存。虚拟地址位数大于物理地址,所以我怀疑64-bit mode下一定要用分页。
寻址方式还是那几种,直接寻址,间接寻址,相对基址+变址等都还是一样。不过有趣的是在64-bit mode下居然可以用RIP(EIP的扩展)作为间址寄存器,理由是,这样可以使开局变量不再需要有一个固定的虚拟地址,而是通过与当前指令在内存中的相对偏移找到全局变量。但这样不就使得程序可以很方便的修改自身代码?可能在页表中有一些保持的措施。
64-bit mode下,指令的默认操作数仍然是32位,这一点我一开始没想到,但现在觉得很有道理,因为一般的程序很少需要使用到64位的整数。如果要让指令使用64位操作数必须加上REX前前缀,机器码0x48。因此以后写C程序用int和用long速度一样,但用int的代码会比较小(虽然变量占用的空间可能一样)。
在使用相对基址(+变址)的寻址方式的时候,除了MOV指令之外,偏移量只可用32位,正负各2G。立即数最大也只能32位,但它可以被指令扩展到64位,也就是说ADD RAX,1234567依然是可以的。但对于MOV指令,既可用64位偏移,也可用64位立即数,这是必然的,否则怎么进行64位运算?在字节序方面,AMD64仍然使用little endian。
暂时就看了这么多,后面还有很多内容不过得等过了这几天再看了,呵呵。以后有什么有趣的我再贴出来:)如果下次要买电脑我一定会选择AMD64了。
发表于 2005-5-22 09:49:29 | 显示全部楼层
Post by Tetris
新的AMD64 CPU扩展了原有的几个通用寄存器至64位,把原有寄存器名开头的"E"变成了"R",例如EAX变成RAX,EFLAGS变成RFALGS,总之所有E打头的换成R就是。

这话说得不够准确。AMD并没有用“R”开头的64位寄存器代替“E”开头的32位寄存器。而是为了向后兼容,对32位寄存器进行了64位扩展,形成新的64
位寄存器。这个新的64位寄存器(如RAX)的低32位部分就是对应的32位寄存器(如EAX)。这各intel在从16位的8086扩展到32位的80386时的做法是一致的。也是寄存器EAX的低16位部分就是16位的AX,这个AX又可以分为8位的AH和AL。
回复 支持 反对

使用道具 举报

发表于 2005-5-22 09:49:59 | 显示全部楼层
x86真的到头了……IBM的PowerPC才是王道啊
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-5-22 10:05:35 | 显示全部楼层
Post by kj501
这话说得不够准确。AMD并没有用“R”开头的64位寄存器代替“E”开头的32位寄存器。而是为了向后兼容,对32位寄存器进行了64位扩展,形成新的64
位寄存器。这个新的64位寄存器(如RAX)的低32位部分就是对应的32位寄存器(如EAX)。这各intel在从16位的8086扩展到32位的80386时的做法是一致的。也是寄存器EAX的低16位部分就是16位的AX,这个AX又可以分为8位的AH和AL。


对啊,所以我用了“扩展”。
回复 支持 反对

使用道具 举报

发表于 2005-5-22 13:18:37 | 显示全部楼层
Post by Tetris
最让人兴奋的是,64-bit mode下使用了64位平展地址,80386下最让人头痛的段选择子+段内偏移的方式终于可以彻底告别。而段寄存器也几乎没有什么作用了,但在某下特别应用下可以通过设置段寄存器在64-bit mode使用32位地址。

linux 已经很少使用段了
可以看一个有趣的现象(注意95行):

     84 #define SAVE_ALL \
     85     cld; \
     86     pushl %es; \
     87     pushl %ds; \
     88     pushl %eax; \
     89     pushl %ebp; \
     90     pushl %edi; \
     91     pushl %esi; \
     92     pushl %edx; \
     93     pushl %ecx; \
     94     pushl %ebx; \
     95     movl $(__USER_DS), %edx; \
     96     movl %edx, %ds; \
     97     movl %edx, %es;
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-5-23 05:02:54 | 显示全部楼层
Post by rickxbx
linux 已经很少使用段了
可以看一个有趣的现象(注意95行):

     84 #define SAVE_ALL \
     85     cld; \
     86     pushl %es; \
     87     pushl %ds; \
     88     pushl %eax; \
     89     pushl %ebp; \
     90     pushl %edi; \
     91     pushl %esi; \
     92     pushl %edx; \
     93     pushl %ecx; \
     94     pushl %ebx; \
     95     movl $(__USER_DS), %edx; \
     96     movl %edx, %ds; \
     97     movl %edx, %es;


Linux下所有的段起始都是0,大小都是4G,所以和平展地址没什么区别。
__USER_DS是用户数据段选择子,所有用户空间的数据段都用这个。另外还有像__KERNEL_DS,__USER_CS等等。从段选择子可以找到选描述字,在Linux下这些段描述字的起始地址,段限,粒度等都一样,不同的是特权级,方向,读/写/执行权限等。Linux没有使用局部段描述字,因此对用户进程之间的隔离是通过页表的保护来进行。
上面的代码是正在从内核态向用户态切换吧?
回复 支持 反对

使用道具 举报

发表于 2005-5-23 09:00:54 | 显示全部楼层
Post by Tetris
上面的代码是正在从内核态向用户态切换吧?


呵呵,猜错了. 是从用户态向核心态时的代码,所以我称之为"有趣"
可能这是个失误,也有可能是提醒我们 "嘿,对 段这个东西,别太在意!"
事实时,用这样的代码编译出来的内核是能够正常运行的.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-5-23 11:28:17 | 显示全部楼层
Post by rickxbx
呵呵,猜错了. 是从用户态向核心态时的代码,所以我称之为"有趣"
可能这是个失误,也有可能是提醒我们 "嘿,对 段这个东西,别太在意!"
事实时,用这样的代码编译出来的内核是能够正常运行的.


呵呵,强烈怀疑这段代宏从来就没有被展开过,怎么可能是
movl %edx, %ds
ds是16位寄存器,上面的指令编译都不过。
回复 支持 反对

使用道具 举报

发表于 2005-5-23 12:06:37 | 显示全部楼层
Post by Tetris
呵呵,强烈怀疑这段代宏从来就没有被展开过,怎么可能是
movl %edx, %ds
ds是16位寄存器,上面的指令编译都不过。

确实有展开的.
至于 movl %edx,%ds 是能够通过编译的, 顶多是个warning, 不过warning 也不见到.估计是编译选项作了点动作.
回复 支持 反对

使用道具 举报

发表于 2005-5-30 10:15:03 | 显示全部楼层
版主提供的AMD64的程序员手册在那里啊?我也想学习学习啊
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表