7

我坚信从学习一门新语言中获得的最重要的东西之一不是如何使用一门新语言,而是你从中获得的概念知识。我不是在问你认为 Assembly 有多重要或有用,我也不关心我是否从未在我​​的任何实际项目中使用它。

我想知道的是您认为对于任何普通程序员来说最重要的汇编概念是什么?它不必与 Assembly 直接相关——它也可能是您认为将所有时间都花在高级语言上的典型程序员无法理解或认为理所当然的东西,例如 CPU 缓存。

4

9 回答 9

7

注册分配和管理

汇编可以让您很好地了解 CPU 可以同时处理多少个变量(机器字大小的整数)。如果你可以分解你的循环,使它们只涉及几个临时变量,它们都可以放入寄存器中。如果没有,您的循环将随着事物被换出到内存而缓慢运行。

这确实帮助了我的 C 编码。我尽量让所有的循环都紧凑而简单,尽可能少的意大利面。

x86 很笨

学习了几种汇编语言让我意识到 x86 指令集是多么的蹩脚。可变长度指令?难以预测的时机?非正交寻址模式?啊。

如果我们都运行 MIPS,我认为,甚至是 ARM 或 PowerPC,世界会更好 :-) 或者更确切地说,如果英特尔/AMD 采用他们的半导体专业知识并用它来制造多核、超快、超便宜的 MIPS处理器而不是具有所有这些可取之处的 x86 处理器。

于 2008-10-01T03:46:21.953 回答
5

我认为汇编语言可以教你很多小东西,以及一些大概念。

我将在这里列出一些我能想到的东西,但没有什么可以替代学习和使用 x86 和 RISC 指令集。

您可能认为整数运算是最快的。如果您想找到整数的整数平方根(即 floor(sqrt(i))),最好使用仅整数近似例程,对吗?

不。数学协处理器(在 x86 上)有一条fsqrt指令。转换为浮点数、取平方根并再次转换为 int 比全整数算法更快。

还有一些事情,比如访问内存,你可以遵循,但不能正确理解,直到你深入研究汇编。假设您有一个链接列表,并且列表中的第一个元素包含一个您需要经常访问的变量。该列表很少重新排序。好吧,每次您需要访问该变量时,您都需要加载指向列表中第一个元素的指针,然后使用它加载变量(假设您不能在两次使用之间将变量的地址保存在寄存器中) . 如果您将变量存储在列表之外,则只需要一次加载操作。

当然,现在在这里节省几个周期通常并不重要。但是,如果您打算编写需要快速的代码,那么这种知识既可以应用于内联汇编,也可以应用于其他语言。

调用约定怎么样?(一些汇编程序会为您处理这个问题——真正的程序员不使用这些。)调用者或被调用者是否清理堆栈?你甚至使用堆栈吗?您可以在寄存器中传递值 - 但由于有趣的 x86 指令集,最好在某些寄存器中传递某些东西。哪些寄存器将被保留?C 编译器自己无法真正优化的一件事是调用。

有一些小技巧,比如 PUSH 一个返回地址,然后 JMP 进入一个过程;当程序返回时,它将转到 PUSHed 地址。这种对函数调用的通常思维方式的背离是另一种“启蒙状态”。如果你曾经设计过一种具有创新功能的编程语言,你应该知道硬件能够做的有趣的事情。

汇编语言知识可以教给您有关计算机安全的特定于体系结构的知识。您如何利用缓冲区溢出或闯入内核模式,以及如何防止此类攻击。

然后是自我修改代码的超级酷,以及作为相关问题的机制,例如重定位和对代码应用补丁(这也需要研究机器代码)。

但是所有这些事情都需要正确的心态。如果你是那种能把

while(x--)
{
  ...
}

一旦你学会了它的作用,但发现自己很难弄清楚它的作用,那么汇编语言可能会浪费你的时间。

于 2008-11-05T00:49:31.933 回答
4

了解汇编语言是很好的,这样可以更好地了解计算机“幕后”是如何工作的争取找出问题所在的机会。但是,尝试将低级知识应用于高级编程语言,例如尝试利用 CPU 缓存指令的方式,然后编写不稳定的高级代码来强制编译器生成超高效的机器代码,这可能是表明您正在尝试进行微优化。在大多数情况下,通常最好不要试图超越编译器,除非您需要提高性能,在这种情况下,您最好还是在汇编中编写这些位。

因此,为了更好地理解事物的工作原理,了解汇编是件好事,但获得的知识不一定直接适用于您如何用高级语言编写代码。然而,在这一点上,我发现学习函数调用如何在汇编代码级别工作(了解堆栈和相关寄存器,了解参数如何在堆栈上传递,了解自动存储的工作原理等)可以做到更容易理解我在高级代码中遇到的问题,例如“堆栈空间不足”错误和“无效调用约定”错误。

于 2008-09-28T22:48:00.907 回答
3

最重要的概念是 SIMD,并创造性地使用它。正确使用 SIMD 可以在从字符串处理到视频处理再到矩阵数学的各种应用中带来巨大的性能优势。与纯 C 代码相比,您可以获得超过10 倍的性能提升——这就是为什么汇编在单纯的调试之外仍然有用的原因。

我从事的项目中的一些示例(所有数字都是 Core 2 上的时钟周期数):

逆 8x8 H.264 DCT(频率变换):

c: 1332
mmx: 187
sse2: 127

8x8 色度运动补偿(双线性插值滤波器):

c: 639
mmx: 144
sse2: 110
ssse3: 79

4 16x16 Sum of Absolute Difference 运算(运动搜索):

c: 3948
mmx: 278
sse2: 231
ssse3: 215

(是的,没错——比 C 快 18 倍以上!)

16x16 块的均方误差:

c: 1013
mmx: 193
sse2: 131

16x16 块的方差:

c: 783
mmx: 171
sse2: 106
于 2008-09-29T01:21:02.880 回答
2

内存、寄存器、跳转、循环、移位和可以在汇编程序中执行的各种操作。我不会怀念调试我的汇编语言类程序的日子——它们很痛苦!- 但它确实给了我一个很好的基础。

我们忘记了(或者永远不知道,也许)我们今天使用的所有这些花哨的东西(而且我喜欢!)最终归结为所有这些东西。

现在,我们当然可以在不了解汇编程序的情况下拥有一份富有成效和利润丰厚的职业,但我认为了解这些概念是件好事。

于 2008-09-28T22:33:21.490 回答
1

我想说,在汇编中学习递归和循环教会了我很多东西。它让我理解了我正在使用的语言的编译器/解释器如何将事物推入堆栈并在需要时将它们弹出的基本概念。我还学会了如何利用臭名昭著的堆栈溢出。(在 C 中使用一些 get- 和 put- 命令仍然非常容易)。

除了在日常情况下使用 asm 之外,我认为我不会使用程序集教给我的任何概念。

于 2008-09-29T01:32:01.077 回答
0

如今,x86 asm 不再是 CPU 内部的直接线路,而更像是一个 API。您编写的汇编器操作码本身被编译成完全不同的指令集,重新排列、重写、修复,并且通常被破坏得面目全非。

因此,学习汇编程序并不能让您对 CPU 内部发生的事情有一个基本的了解。恕我直言,比学习汇编程序更重要的是要很好地了解目标 CPU 和内存层次结构的工作原理。

系列文章非常彻底地涵盖了后一个主题。

于 2008-09-28T22:34:08.943 回答
0

我会说寻址模式非常重要。

我的母校把它发挥到了极致,因为 x86 没有足够的它们,我们在 PDP11 的模拟器上研究了所有东西,我记得至少有 7 个。回想起来,这是一个不错的选择。

于 2008-09-29T01:10:05.933 回答
0

定时

快速执行:

  • 并行处理
  • 简单说明
  • 查找表
  • 分支预测,流水线

快速到慢速访问存储:

  • 寄存器
  • 缓存,以及各种级别的缓存
  • 内存堆和栈
  • 虚拟内存
  • 外部输入/输出
于 2008-09-29T02:11:36.177 回答