bec*_*cks 8 assembly x86-64 intel
我尝试用示例或一本好书来搜索intel x64汇编教程,但我甚至没有在intel站点中找到它.
所以,你能给我一个很好的教程或书吗?我在linux上使用nasm.
谢谢
Fra*_*kH. 15
不可否认,你喜欢学习编程是个人偏见.
但特别是对于汇编语言,我发现一种方法对我来说比阅读指令集参考手册和/或汇编语言书籍(它们存在的地方)更有用.
我通常做的是弄清楚装配工作如何在我尚未使用的操作系统平台上为我所知的新CPU/CPU是利用开发人员工具链.像那样:
为目标CPU安装一个(交叉)编译器和反汇编程序.这些天,GNU gcc/binutils无处不在常常意味着gcc和objdump -d.
创建一堆小程序/小块源代码,如:
extern int funcA(int arg);
extern int funcB(int arg1, int arg2);
extern int funcC(int arg1, int arg2, int arg3);
extern int funcD(int arg1, int arg2, int arg3, int arg4);
extern int funcE(int arg1, int arg2, int arg3, int arg4);
extern int funcF(int arg1, int arg2, int arg3, int arg4, int arg5);
extern int funcG(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6);
extern int funcH(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6,
int arg7);
int main(int argc, char **argv)
{
printf("sum of all funcs: %d\n",
funcA(1) + funcB(2, 3) + funcC(4, 5, 6) + funcD(7, 8, 9, 10) +
funcE(11, 12, 13, 14, 15) + funcF(16, 17, 18, 19, 20, 21) +
funcG(22, 23, 24, 25, 26, 27, 28) + funcH(29, 30, 31, 32, 33, 34, 35));
return 12345;
}Run Code Online (Sandbox Code Playgroud)
使用编译器优化编译这些并反汇编生成的目标代码.
代码的结构很简单,足以演示ABI如何表现.以函数调用,传递参数和返回值,管理寄存器空间 WRT.在进行函数调用时保留/ volatile的寄存器.它还将向您展示一些用于初始化常量数据的基本汇编代码,以及像堆栈访问和管理一样的"粘合".
为简单的C语言结构(如循环和if/ else或switch语句)扩展它.始终保持对外部未定义功能几个电话,因为这样做会防止编译器优化,从扔你所有的"测试代码"出来的,而当你使用if()的测试switch()上,谓词argc(或其他功能参数),因为编译器无法预测,要么(并因此"古怪地"优化代码的构建块.
为了找出编译器如何在内存中排列这些,使用哪些汇编指令来访问字节/单词/整数/长整数/浮点数等,使用struct {}和class {}包含不同原始数据类型序列的定义进行扩展.
所有这些测试你可以故意改变代码(比如,使用不同的操作+),和/或使代码更复杂,以便更多地了解指令集和ABI的特定部分.
完成后,查看输出,找到平台ABI的副本(电子或非电子).其中包含有关如何完成上述操作的原则/为何以这种方式完成的规则手册,它将帮助您了解这些规则适用于特定平台的原因.了解上述内容至关重要,因为当您编写自己的汇编代码时,您必须将其与其他非汇编代码接口(除非是纯演示).这就是你需要遵守规则的地方,所以即使你不了解它们,至少要知道规则手册的位置.
只有在那之后,我才会建议您实际查找特定平台的指令集参考.
那是因为当你经历了上面的第一次,那么你已经获得了足够的经验/你已经看到足够的开始使用一个小的C程序,将其编译成汇编源,稍微修改一下,汇编并链接它看看你的修改是否符合预期.
在那个阶段尝试使用一些更不常见/专业的指令会更容易,因为你已经看到函数调用是如何工作的,需要什么样的粘合代码才能使程序集与程序的其他部分接口,你'已经使用过工具链,所以你不需要再从头开始了.
即,总而言之,我的建议是从上到下而不是从下到上学习装配.
边注:
为什么我在为这些简单的例子分析编译器生成的汇编代码时建议使用编译器优化?
好吧,答案就是因为,与某些人违反直觉,如果你让编译器优化地狱,那么生成的汇编代码要简单得多.如果没有优化,编译器通常会创建"愚蠢"的代码,例如将所有变量放入堆栈,保存并从那里恢复它们无缘无故地看到,注册保存/恢复/初始化只是为了覆盖下一条指令和许多更多这样的事情.因此,发出的代码量要大得多.它充满了残酷,更难理解.编译器优化强制将这个问题修改为必要的,这是你想要了解的平台ABI和装配.因此,使用编译器优化.