学习汇编对编程有何帮助?[关闭]


132

我使用高级语言(Python,C#,VBA,VB.NET)编程已有大约10年的时间,而对于“幕后”所发生的事情,我完全不了解。

我想知道学习汇编的好处是什么,对作为程序员的我有什么帮助?您能否提供给我一个资源,向我展示我在高级代码中编写的代码与汇编中发生的代码之间的确切联系?


2
如果您真的想了解代码的深层内容,则可以参阅Intel处理器手册(仅介绍部分):download.intel.com/products/processor/manual/325462.pdf。也许这比您想要的要深一些,但是我发现它很有用。
superM 2012年

4
如果您想知道在.Net中专门发生的情况,您可能想了解有关CIL的更多信息。它在某些方面类似于组装,但是更高层次。因此,比实际组装更容易理解。
svick

6
如果您学习汇编语言,则可以for通过在循环之外声明变量来避免想到优化循环。示例
StriplingWarrior

7
哦,我的上帝。您刚刚使我想起了大约一年前我在大学上的汇编语言课。看到我们理所当然地将极其简单的内容翻译成成百上千个甚至更小,更底层的操作,真是令人惊讶。计算机是非凡的机器。
Radu Murzea

14
学习汇编将使您对编程语言的概念产生深切而持久的热爱,这种编程语言使您无需再编写汇编中的复杂代码。
沙杜尔

Answers:


188

因为您会了解它如何工作的。

  • 您将了解函数调用不是免费的,以及为什么调用堆栈会溢出(例如,在递归函数中)。您将了解如何将参数传递给函数参数,以及参数的实现方式(复制内存,指向内存)。
  • 您将了解内存不是免费的,自动内存管理的价值是多么宝贵。内存并不是您“仅拥有”的东西,实际上,它需要管理,照顾和最重要的是,不要忘记(因为您需要自己释放它)。
  • 您将了解控制流如何在最基本的级别上工作。
  • 您将更欣赏高级编程语言中的构造。

归结为,我们用C#或Python编写的所有内容都需要转换为计算机可以执行的一系列基本操作。在类,泛型和列表理解方面很容易想到计算机,但是这些仅存在于我们的高级编程语言中。

我们可以想到看起来很不错但不能很好地转换为低级工作方式的语言构造。通过了解它的真正工作原理,您将更好地理解事情为什么以它们的方式工作。


12
+1表示“您将更欣赏高级编程语言中的结构”。好答案。
DevSolo 2012年

42
除了经过几周的asm训练之后,您将开始把C视为高级编程语言。除非您要与低级别的嵌入式设备开发人员交谈,否则大声说出来会使大多数人认为您有点疯狂。
丹·尼利

19
@Dan:这些术语如何随时间变化有点有趣。20年前,当我刚开始编程时,是否曾问过别人他们会说“当然C是一种高级语言!”。那应该很明显;它提供了标准化的堆和内存访问模型。这是对硬件的严重抽象。在低级语言中,您必须自己跟踪所有内存地址,或者如果您正在做一些真正想做的事,则可以编写自己的堆分配器!所以我想知道,今天使事物高层次或低层次的标准是什么?
梅森惠勒2012年

9
高级/低级不是二进制文件。一个在自己的职业生涯中既编写汇编语言又编写Python的全面的程序员可能会认为C或C ++是中级语言。
罗素·博罗戈夫

6
这些是要理解的重要内容,但是很容易从抽象的层次上加以介绍:例如,在机器指令级别的计算机入门课程中。我不是汇编程序员,但如果我自己这么说的话,我会很好地理解它们。在一些SO答案中,我看到了有关指令高速缓存和流水线的讨论,而这些确实使我头疼。但是(到目前为止)答案中缺少该子指令级别。那么,与学习基础课程相比,实际学习汇编程序编程有什么好处?
alexis

33

通常,它将使您更好地理解“幕后”以及指针如何工作以及寄存器变量和体系结构的含义(内存分配和管理,参数传递(按值/按引用)等)。

快速浏览C,这是怎么回事?

#include <stdio.h>

main()
{
  puts("Hello World.");
  return(0);
}

进行编译gcc -S so.c并查看以下程序集的输出so.s

 $ cat so.s

    .file   "so.c"
    .section    .rodata
.LC0:
    .string "Hello World."
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    $.LC0, (%esp)
    call    puts
    movl    $0, %eax
    leave
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"
    .section    .note.GNU-stack,"",@progbits

2
+1:提示!通过查看C编译器的功能,您可以学到很多东西。
乔治

8
... SOS是故意的吗?(寻求帮助等)
Izkata 2012年

1
@Izkata哈哈..好一个,我什至没有注意到。我有一个so.c用于处理stackoverflow问题的标准文件(例如我有so.pyso.awk等等),以快速测试事物。So.S .. :)
Levon

9
如果进行编译,则gcc -O -c -g -Wa,-ahl=so.s so.c可以看到每行C代码的汇编输出。这使得了解正在发生的事情变得容易一些。
Mackie Messer 2012年

1
是的,输出很长。您可以搜索5:so.c以找到的第5行的代码so.c
Mackie Messer

30

我认为您在这里找到的答案是:http : //www.codeproject.com/Articles/89460/Why-Learn-Assembly-Language

文章引用:

尽管这是事实,但您可能不会发现自己在汇编中编写下一个客户的应用程序,但是学习汇编仍然有很多好处。如今,汇编语言主要用于直接硬件操纵,访问专用处理器指令或解决关键性能问题。典型用途是设备驱动程序,低级嵌入式系统和实时系统。

事实是,高级语言变得越复杂,并且写入的ADT(抽象数据类型)越多,支持这些选项的开销就越大。在.NET实例中,可能是膨胀的MSIL。想象一下,如果您知道MSIL。这是汇编语言的亮点。

汇编语言与程序员一样接近于处理器,因此精心设计的算法非常出色-汇编对于速度优化非常有用。一切都与性能和效率有关。汇编语言使您可以完全控制系统资源。就像组装线一样,您编写代码以将单个值压入寄存器,直接处理内存地址以检索值或指针。

用汇编语言编写是要确切地了解处理器和内存如何协同工作以“使事情成真”。请注意,汇编语言是神秘的,应用程序源代码的大小比高级语言大得多。但是请不要误会,如果您愿意花费时间和精力进行装配,那么您会变得更好,并且会在现场脱颖而出。

另外,我会推荐这本书,因为它具有简化的计算机体系结构版本:计算系统简介:从位和闸到C和其他,2 / e Yale N. Patt,德克萨斯大学奥斯汀分校的Sanjay J. Patel,伊利诺伊大学香槟分校


7
这描述了ASM的用途,并提到了HLL膨胀,但是学习ASM的唯一特定好处是编写超快速代码。是的,但是即使您学习了ASM,您实际将其纳入应用程序的可能性有多大?假设您编写的是业务应用程序,而不是硬件控制器或设备驱动程序。

+1 @notkilroy,感谢您的链接,尤其是书的推荐
安东尼

2
@Jon,我真的不明白为什么要开发商务软件。如果您是DBA或正在编写编译器,或者内存空间有限,那是一回事,但是我认为没有多少人经常接触它。优化主要由编译器负责,这是在汇编中编写的最大原因。有时在跟踪内存泄漏时很有用。
Brynne

由于我专门研究业务应用程序,因此我主要依靠使用4GL的基于SQL的应用程序开发工具。它们使我能够快速创建应用程序原型并将其自定义到生产系统中。很少需要编写可调用的cfunc。交付时间和修改时间是我世界中的重要因素!
Frank R.

2
我完全不同意。自动化优化器通常可以在创建快速程序集方面击败人类程序员。
DeadMG

22

以我的拙见,它没有太大帮助。

我曾经非常了解x86组装。当我的课程中出现汇编时,它会有所帮助,在面试中它会出现一次,并帮助我证明编译器(Metrowerks)正在生成不良代码。计算机的实际运行方式令人着迷,而学习它使我在智力上更加丰富。当时玩起来也很有趣。

但是,当今的编译器比几乎任何代码段上的任何人都更擅长生成汇编。除非您正在编写编译器或检查编译器在做正确的事情,否则您可能会通过学习它来浪费时间。

我承认,C ++程序员仍然有用地提出的许多问题都是通过了解汇编来解决的。例如:我应该使用堆栈变量还是堆变量?我应该按值或const引用传递?但是,我认为在几乎所有情况下,这些选择都应该基于代码的可读性而不是节省计算时间。(例如,只要您想将变量限制为作用域,就使用堆栈变量。)

我的卑微​​建议是专注于真正重要的技能:软件设计,算法分析和问题解决。凭着开发大型项目的经验,您的直觉将得到改善,这比了解装配(我认为)要多得多。


2
我不同意 如果您对某种算法有广泛的了解,并且对硬件有很好的了解,通常可以创建比编译器可以更好地优化的汇编代码,因为它必须安全运行。在进行优化时,大致了解代码如何转换为程序集也很有帮助。
Leo

优化不是学习它的原因。在这方面,我同意尼尔·G(Neil G)的观点。他低估了他对真实机器的基本了解如何告知他如何使用高级语言。
沃伦·P

以我的经验,通过实现,测量事物,寻找方法来优化它,实现更好的方法等,可以使算法快速完成。组装的问题是实现需要花费很多时间,因此您不会有机会反复细化。
gnasher729

如今,很少要用汇编进行编码的情况,但是了解其工作原理是非常宝贵的,对于那些想知道其全部工作原理的人来说将大有帮助。例如,当我不知道事情为什么会发生时,我发现很难追踪事情。
温格·森顿

21

您应该熟悉所使用系统中的一个“更深层次”。一口气跳得太远也不错,但可能没有人们期望的那样有用。

使用高级语言的程序员应该学习较低级别的语言(C是一个很好的选择)。当您告诉计算机实例化一个对象,创建一个哈希表或一个集合时,无需一路进行汇编就可以了解幕后的情况,但是您应该能够编写代码他们。

对于Java程序员,学习一些C语言可以帮助您进行内存管理,传递参数。用C编写一些扩展的Java库将有助于理解何时使用Set的实现(您要散列还是树?)。在线程环境中处理char *将有助于理解为什么String是不可变的。

进入下一个层次... AC程序员应该对汇编有一定的了解,并且汇编类型(通常在嵌入式系统商店中可以找到)在理解门级的东西方面可能做得很好。那些与盖茨合作的人应该了解一些量子物理学。而且那些量子物理学家,他们仍然在努力弄清楚下一个抽象是什么。


1
更深一层是关于正确的。我倾向于花一些时间,但是假设与为C#程序员学习MSIL相比,x86汇编知识值得投资。作为一个在大学学习组装和固态物理学的人,我不认为了解门设计的物理知识对我有帮助,除了毕业于电子学位。
Muhammad Alkarouri

@MuhammadAlkarouri我的思路是理解电流泄漏,运行时间,电阻以及热量对系统的影响。对基本“为什么”的理解比起最小迹线分隔和操作公差的规则,有助于做出更多决策。

5

由于您没有使用已知的语言提及C或C ++,因此请列出。我强烈建议您甚至在考虑组装之前就对它们进行充分的学习。C或C ++将提供在托管语言中完全透明的所有基本概念,并且您将了解本页面中提到的大多数概念,以及可以在现实世界项目中使用的最重要的语言之一。这是您编程技能的真正附加值。请注意,汇编程序在非常特定的领域中使用,它几乎没有C或C ++有用。

我什至更进一步地说,在了解非托管语言的工作原理之前,您不应该投入汇编。这几乎是必读的。

如果您想更进一步,则应该学习汇编。您想知道如何精确地创建每种语言的构造。它提供了很多信息,但级别复杂性却大不相同。


5

如果您精通一门语言,那么您至少应该对技术的基础知识至少低一个抽象级别。

为什么?当出现问题时,对基本机制的了解使调试奇怪的问题变得容易得多,自然可以编写效率更高的代码

以Python(/ CPython)为例,如果您开始遇到怪异的崩溃或性能下降,则有关如何调试C代码的知识可能非常有用,这与引用计数内存管理方法的知识相同。这也将帮助您知道何时/是否将某些内容编写为C扩展,依此类推...

在这种情况下要回答您的问题,汇编的知识确实并不能帮助经验丰富的Python开发人员(抽象步骤太多了-用Python完成的任何操作都会导致许多汇编指令)

..但是,如果您有C的经验,那么了解“下一级”(汇编)确实很有用。

同样,如果您使用的是CoffeScript,那么了解Javascript非常有用。如果您正在使用Clojure,则对Java / JVM的了解很有用。

这个想法在编程语言之外也可以使用-如果您使用的是Assembly,那么熟悉底层硬件的功能是一个好主意。如果您是一名Web设计人员,那么最好了解如何实现Web应用程序。如果您是汽车修理工,那么了解一些物理知识是一个好主意


3

编写一个小的c程序,然后反汇编输出。就这样。但是,为增加或减少为操作系统的利益而添加的“内务处理”代码做好准备。

汇编可以帮助您了解引擎盖下发生的事情,因为它直接处理内存,处理器寄存器等。

如果您真的想裸奔而又没有使操作系统复杂化的所有事情,请尝试使用汇编语言Arduino进行编程。


3

没有确切的答案,因为程序员并非全部。您是否需要知道潜伏在下面的东西?如果是这样,然后学习它。您只是出于好奇而只想学习它吗?如果是这样,然后学习它。如果这对您没有实际的好处,那为什么要麻烦呢?仅仅为了开车就需要机械师的知识水平吗?机械师是否仅需要在汽车上工作就需要工程师的知识水平?这是一个严肃的类比。技工可以是一个非常出色的生产技工,而无需深入了解工程师所掌握的车辆。音乐也一样。您是否真的想把旋律,和声和节奏的复杂性变成一个好的歌手或演奏者?不会。一些非常有才华的音乐家不会读一点乐谱,更不用说告诉您Dorian和Lydian模式之间的区别了。如果您愿意,可以,但是不需要。如果您是一名Web开发人员,那么我可以想到的程序集没有实际用途。如果您是在嵌入式系统中或真的很特殊的环境中,则可能有必要,但如果确实如此,您就会知道。

这是乔尔采用非高级语言的这些价值:http : //www.joelonsoftware.com/articles/ThePerilsofJavaSchools.html


2

实际上,最适合您的可能是一个(据我所知)在任何地方都不存在的类:该类将机器/汇编语言和存储寻址概念的简要概述与编译器构造的导览结合在一起,代码生成和运行时环境。

问题是,使用高级,远离硬件的语言(如C#或Python),您并不会真正欣赏这样一个事实,即您所做的每一步都会变成成百上千的机器指令,而您却没有往往无法理解几行高级语言如何导致大量存储空间的访问和修改。您所需要的不只是精确地了解“幕后花絮”所发生的事情,而是需要了解正在发生的事情的范围以及对所发生事情的类型的一般概念。


1

我对这个问题的回答相对较新。现有的答案涵盖了我过去所说的内容。实际上,这仍然是最重要的答案 -“赞赏高级编程中的结构”,但这是我认为值得一提的特例。

根据引用研究的Jeff Atwood博客文章,了解分配是理解编程的关键问题。学习者程序员可能会理解该符号仅表示计算机遵循的步骤以及这些步骤所引起的原因,或者会因误导数学方程式等而永久困惑。

好吧,如果您了解6502汇编程序的以下内容...

LDA variable
CLC
ADC #1
STA variable

那真的只是步骤。然后,当您学习将其转换为赋值语句时...

variable = variable + 1;

您不需要与数学方程式产生误导性的类比-您已经有了一个正确的心理模型可以将其映射到。

编辑 -当然,如果您得到的解释LDA variable基本上是ACCUMULATOR = variable,而这恰恰是您从某些教程和参考资料中获得的解释,那么您最终会回到起点,这对您毫无帮助。

我学习了6502汇编程序作为第二语言,第一种是Commodore Basic,那时我并没有真正学到很多东西-部分是因为学习的东西很少,而且因为汇编程序看起来比以前有趣得多。一部分是时间,部分是因为我是14岁的怪胎。

我不建议做我想做的事情,但是我想知道,用一种非常简单的汇编语言学习一些非常简单的示例是否可能是学习高级语言的一个有价值的入门。


0

除非您是编译器作者,或者需要高度优化的知识(例如数据处理算法),否则学习汇编代码将不会给您带来任何好处。

编写和维护用汇编语言编写的代码非常困难,因此,即使您非常了解汇编语言,除非没有其他方法,否则也不要使用它。

针对SSE进行优化:案例研究 ”一文显示了组装后可以执行的操作。作者设法将算法从100个周期/向量优化到17个周期/向量。


1
作者没有在C ++版本中使用任何矢量指令或内在函数。您不需要汇编程序来编写SSE代码。
gnasher729

@ gnasher729是的,您不需要。但是使用汇编,程序可以运行得更快。毕竟,人类比编译器更聪明(在极少数情况下)。
2015年

0

由于细节(寄存器分配等)的原因,汇编语言的编写不会给您神奇的速度提高,您可能会编写有史以来最简单的算法。

此外,对于现代(读取-在70-80年代后设计的)处理器组装,您将无法获得足够的详细信息来了解正在发生的事情(也就是说-在大多数处理器上)。就调度指令而言,现代的PU(CPU和GPU)非常复杂。了解汇编(或伪汇编)的基础知识将有助于理解计算机体系结构的书籍/课程,这些书籍/课程将提供更多的知识(缓存,无序执行,MMU等)。通常,您不需要了解复杂的ISA就可以理解它们(MIPS 5是非常流行的IIRC)。

为什么要了解处理器?它可以使您更多地了解正在发生的事情。假设您以幼稚的方式编写矩阵乘法:

for i from 0 to N
    for j from 0 to N
        for k from 0 to N
            A[i][j] += B[i][k] + C[k][j]

对于您的目的,它可能“足够好”(如果它是4x4矩阵,则无论如何都可以编译为矢量指令)。但是,在编译大量数组时,会有一些非常重要的程序-如何对其进行优化?如果您使用汇编语言编写代码,则可能会有所改善(除非您像大多数人那样做-同样以幼稚的方式,未充分利用寄存器,不断地将数据加载/存储到内存中,实际上程序速度比HL语言慢) 。

但是,您可以反转线并神奇地获得性能(为什么?我将其保留为“家庭作业”)-IIRC取决于大型矩阵的各种因素,甚至可能达到10倍。

for i from 0 to N
    for k from 0 to N
        for j from 0 to N
            A[i][j] += B[i][k] + C[k][j]

话虽如此-正在进行的编译器工作能够做到这一点(石墨用于gcc,波利用于使用LLVM的任何程序)。他们甚至有能力将其转换为(抱歉-我正在写对内存的阻止):

for i from 0 to N
    for K from 0 to N/n
        for J from 0 to N/n
            for kk from 0 to n
                for jj from 0 to n
                    k = K*n + kk
                    j = J*n + jj
                    A[i][j] += B[i][k] + C[k][j]

总而言之-了解程序集的基础知识可以使您从处理器设计中挖掘各种“细节”,从而可以编写更快的程序。了解RISC / CISC或VLIW /矢量处理器/ SIMD / ...体系结构之间的差异可能会很好。但是,我不会从x86开始,因为它们往往非常复杂(可能也是ARM)-知道什么是寄存器等,恕我直言足以启动。


我发现您提供了几个代码示例很有趣,但是它们都不是汇编语言。
罗伯特·哈维

-1

通常,对于调试而言,这非常重要。当系统在指令中间中断并且错误没有意义时,您该怎么办?只要您只使用安全的代码,.NET语言的问题就不那么多了-系统几乎总是使您免受幕后操作的困扰。


-2

简而言之,我认为答案是因为如果您学习汇编,可以做更多的事情。学习汇编可以访问嵌入式设备编程,安全性渗透和规避,逆向工程和系统编程等领域,如果您不了解汇编器,则很难进行这些工作。

至于学习它以提高程序性能,这在应用程序编程中值得怀疑。在大多数情况下,在达到此优化级别之前,有很多事情需要首先关注,例如优化磁盘和网络上的I / O访问,优化构建GUI的方式,选择正确的算法,最大化所有核心,如果要以最好的硬件来运行,就可以购买并从解释语言转换为编译语言。除非您要为其他最终用户创建软件,否则与程序员的小时工资相比,硬件是便宜的,尤其是在云可用性方面。

同样,在遇到总线故障,退出或返回代码库以在写完最后一个版本一年后更改代码后,还必须权衡提高程序执行速度和代码的可读性。


-3

我会建议学习算法:排序,链表,二叉树,哈希等。

另请参阅Lisp,请参阅《计算机程序的结构和解释》 groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures该视频课程将教您所有需要了解的内容,包括算法(如何根据一些原始命令,一个Lisp原语和一些汇编程序挑衅)。

最后,如果您必须学习汇编程序,请学习一种简单的程序,例如ARM(它在x86上使用的设备大约多于4倍)。


-8

答案是,仅因为所使用的语言必须在最后解释或编译为汇编器即可。无论是语言还是机器。

语言的设计源自CPU的工作方式。低级程序更多,高级程序更少。

最后,我要说的不仅是您需要了解很少的汇编程序,而且还需要学习汇编程序,从而了解CPU体系结构。

一些示例:许多Java程序员不了解为什么它不起作用,甚至不知道在运行时会发生什么。

String a = "X";
String b = "X";
if(a==b)  
    return true;

如果您知道一些汇编程序,您将始终知道存储位置的内容与“指向”该位置的指针变量中的数字不同。

更糟糕的是,即使在已出版的书籍中,您也会读到类似JAVA原语那样通过值和对象传递引用的情况,这是完全错误的。Java中的所有参数都是按值传递的,Java不能将对象传递给函数,只能将指针传递给值。

如果您现在正在汇编程序,这显然是怎么回事,如果不是,它的解释太复杂了,以至于大多数作者都只是在撒谎。

当然,这些内容的影响很小,但稍后可能会给您带来真正的麻烦。如果您知道汇编程序不是问题,那么如果不是,则表示您将进行漫长的调试工作。


5
您的第一段是完全不正确的:语言没有被编译为ASM,而是被编译为机器代码。解释器也不会编译为ASM,它们会解释代码或字节代码,并在预编译的机器代码上调用函数或方法。

6
您声称有关Java的任何事情都不正确。String a = "X"; String b = "X"; if( a==b) return true;实际上== true,从which 开始是因为String interning编译器执行了某种操作。所有其他Java语句也是错误的。Java没有指针,它有它的引用一样的东西。而且,这些都不以任何方式与汇编程序有关。Java按值传递基元,并按值传递引用。Java没有指针,因此它无法传递任何指针。同样,所有与了解ASM无关。

我一直认为高级语言会编译为对象(机器代码)或伪代码,而不是ASM。
Frank R.

@FrankComputer正确,但是机器代码字节将1:1映射为汇编指令,因此您可以轻松地在代码对象和ASM之间进行转换(反编译或汇编)
dbr 2012年

2
上次使用@FrankComputer时,我将gcc编译后的C / C ++ / fortran / java / ada / etc转换为内部字节码,并将内部字节码转换为汇编器。然后,它将此汇编程序代码分派给汇编程序,以将其转换为机器代码。
ctrl-alt-delor 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.