assembly - Intel X86-64 组装教程或书籍

标签 assembly x86-64 intel

就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the help center为指导。




8年前关闭。




我试图通过示例或一本好书搜索有关英特尔 x64 汇编教程的信息,但我什至在英特尔网站上都没有找到。

所以,你能给我推荐一本好的教程或书吗??
我在 linux 上使用 nasm。

谢谢

最佳答案

诚然,您更喜欢学习编程的方式是个人偏见。

但特别是在汇编语言方面,我发现一种方法对我来说比阅读指令集引用手册和/或汇编语言书籍(如果存在)更有用。

在我尚未使用过的操作系统平台上,我通常要弄清楚组装如何为新 CPU/我未知的 CPU 工作的是利用开发人员工具链。像那样:

  • 为 objective-c PU 安装一个(交叉)编译器和反汇编器。如今,GNU gcc 的/binutils 无处不在通常意味着 gccobjdump -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;
    }
  • 使用编译器优化编译这些并反汇编生成的目标代码。
    代码的结构非常简单,可以演示 ABI 的行为方式。函数调用,传递参数和返回值,管理寄存器空间wrt。进行函数调用时,哪些寄存器被保留/易失。它还将向您展示一些用于初始化常量数据的基本汇编代码,以及诸如堆栈访问和管理之类的“粘合”。
  • 将此扩展为简单的 C 语言结构,如循环和 if/elseswitch声明。始终保留一些对外部未定义函数的调用,因为这样做会阻止编译器优化器抛出所有“测试代码”,并且当您使用 if() 时。 switch() 的测试, 谓词于 argc (或其他函数参数),因为编译器无法预测(因此“奇怪地”优化代码的构建块)。
  • 扩展此使用 struct {}class {}包含不同原始数据类型序列的定义,以便找出编译器如何在内存中安排这些,哪些汇编指令用于访问字节/字/整数/长整数/浮点数等。
    您可以故意更改所有这些测试代码片段(例如,使用与 + 不同的操作),和/或使其更复杂,以了解有关指令集和 ABI 特定片段的更多信息。

  • 完成此操作并查看输出后,找到平台 ABI 的副本(无论是否为电子版)。其中包含有关如何完成上述操作/为什么这样做的规则手册,它将帮助您了解为什么这些规则适用于特定平台。了解上述内容至关重要,因为当您编写自己的汇编代码时,您必须将其与其他非汇编代码进行交互(除非是纯演示)。这就是你需要遵守规则的地方,所以即使你不了解它们,至少知道规则手册在哪里。

    只有在那之后,我才会建议您实际跟踪特定平台的指令集引用。

    那是因为当您首先完成上述操作时,您已经获得了足够的经验/您已经看到了足够的经验,可以从一个小的 C 程序开始,将其编译为汇编源代码,稍作修改,组装并链接它,然后看看你的修改是否做了它应该做的。

    在那个阶段尝试使用一些更不常见/专门的指令会容易得多,因为您已经看到了函数调用的工作原理,需要什么样的胶水代码才能将您的程序集与程序的其他部分连接起来,您已经使用了工具链,因此您不再需要完全从头开始。

    即,总而言之,我的建议是自上而下而不是自下而上学习汇编。

    旁注:

    为什么我建议在分析编译器生成的汇编代码时使用编译器优化来分析这些简单的例子?
    嗯,答案是因为,与某些人的直觉相反,如果让编译器优化一些东西,生成的汇编代码会简单得多。如果没有优化,编译器通常会创建“愚蠢”的代码,例如将所有变量放入堆栈中,无缘无故地从那里保存和恢复它们,注册保存/恢复/初始化只是为了覆盖下一条指令的 reg 以及更多这样的事情。因此,发出的代码量要大得多。它充满了杂乱无章的东西,而且更难理解。编译器优化强制将这些繁琐的内容缩减为必要的内容,这是您希望看到的以了解平台 ABI 和程序集。因此,使用编译器优化。

    关于assembly - Intel X86-64 组装教程或书籍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15297842/

    相关文章:

    linux - 为 Linux 调试

    c++ - 在汇编语言中使用 RGB 颜色

    c - Linux x86_64 汇编套接字编程

    c - int32_t : gcc/linux 86 vs amd64 的对齐要求

    gcc - 几年前构建的gcc版本的编译器如何仍能针对最近发布的处理器进行编译?

    performance - 有效地检查FP位模式是否为整数。根据条件组合,分支速度更快?

    linux - 适用于 Linux 的 AMD 兼容汇编程序

    c++ - 错误共享和原子变量

    linux - 从未对齐 RSP 的函数调用时,glibc scanf 出现段错误

    windows - 如何启动 MeeGo AppDev?