Assembly 很难理解编译器和汇编语言是如何组合在一起的

Assembly 很难理解编译器和汇编语言是如何组合在一起的,assembly,Assembly,这更多的是一个概念性的问题,但我正在为即将到来的项目学习嵌入式系统。我一直在看关于教程要点的教程 这个网页讨论编译器、汇编程序和耦合 基本上:汇编过程如何与编译器协同工作。我在哪里以及如何拼凑这些信息?我没有得到什么?使用gnu工具自己尝试一下 #define FIVE 5 extern unsigned int more_fun ( unsigned int ); unsigned int fun ( void ) { return(more_fun(FIVE)+1); } 保存

这更多的是一个概念性的问题,但我正在为即将到来的项目学习嵌入式系统。我一直在看关于教程要点的教程

这个网页讨论编译器、汇编程序和耦合


基本上:汇编过程如何与编译器协同工作。我在哪里以及如何拼凑这些信息?我没有得到什么?

使用gnu工具自己尝试一下

#define FIVE 5

extern unsigned int more_fun ( unsigned int );
unsigned int fun ( void )
{
    return(more_fun(FIVE)+1);
}
保存临时gcc首先需要预处理以拉入包含并替换定义/宏

# 1 "so.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "so.c"




extern unsigned int more_fun ( unsigned int );
unsigned int fun ( void )
{
    return(more_fun(5)+1);
}
gcc然后调用汇编器将其组装成一个对象。这是汇编程序可以解析的尽可能多的机器代码,再加上调试和链接所需的其他信息。使用反汇编程序,我们可以看到汇编程序生成的代码:

Disassembly of section .text:

00000000 <fun>:
   0:   e92d4010    push    {r4, lr}
   4:   e3a00005    mov r0, #5
   8:   ebfffffe    bl  0 <more_fun>
   c:   e2800001    add r0, r0, #1
  10:   e8bd8010    pop {r4, pc}
节的反汇编。文本:
00000000 :
0:e92d4010推送{r4,lr}
4:e3a00005 mov r0,#5
8:ebfffffe bl 0
c:e2800001加上r0,r0,#1
10:e8bd8010 pop{r4,pc}

中间的BL 0调用MuleLoFun函数没有解决,因为该代码不是原始C源文件的一部分,所以占位符放在那里,链接器稍后会出现……链接…将对象放在一起。如果您没有指定-c,那么gcc也会为您调用链接器

大多数“工具链”都是这样工作的,这是明智的做法。由于“及时”和“为什么要爬山,因为它们在那里”的原因,有些编译器更直接地处理机器代码,但即使是llvm也不这样做,它声称是JIT,尽管它的主要用途是其他方式。工具链不必使用单独的可执行文件,也不必使用各种方法来解决问题

我不记得你链接的网站是否在你应该不惜一切代价避免的网站列表上,有一个或类似的网站有一些非常糟糕的信息,令人困惑和错误。那一页不坏也不混乱,但我只是浏览了一下


反编译器并不以人们希望编译的形式存在,正如您在这个简单的示例中所看到的,原始代码中的信息丢失了,您无法完全从二进制代码中重新创建此代码。制作类似的简单示例来演示这一点非常容易。

这里有一个难题:编译器使用汇编语言为任何目标机器实现高级源代码的逻辑。e、 g.有关查看编译器的asm输出的更多信息,请参阅,尤其是Matt Godbolt的CppCon talk May是一个很好的介绍。(我的答案中有youtube链接)正如你的链接所说:编译器将源代码从高级编程语言转换为低级语言(如汇编语言或机器代码)。这就是关键。如果编译器从(比如)C翻译成汇编语言,您仍然需要一个汇编器将其翻译成机器代码(这是硬件实际需要的)。然而(正如文档所说),有些编译器直接将C翻译成机器代码,不需要汇编@如果编译器可以将汇编语言转换为机器代码,为什么它不能严格地转换为机器代码呢。这是因为从C语言到汇编语言再到机器代码的翻译速度更快吗?仅仅因为编译器可以输出机器代码并不意味着编写编译器的人会选择这样做。为什么不呢?我怀疑是否有“一”个很好的理由来解释为什么一些编译器编写者以一种方式编写而另一些人不这样做。能够检查“中间”阶段可能被视为一种好处。或者能够交换汇编程序。解耦合可能会简化调试。正如你提到的,速度是一个考虑因素。不必编写汇编程序可能会(稍微)容易一些。它甚至可能只是“我们一直都是这样做的,没有人记得为什么。”IIRC tutorialspoint的NASM主题有点有毒,所以这可能就是你记得的“避免”的网站。但是具体的教程是由不同的作者完成的,所以OP使用的那个也许是可以的。。。这是互联网,每个人都应该是偏执狂。。。。
Disassembly of section .text:

00000000 <fun>:
   0:   e92d4010    push    {r4, lr}
   4:   e3a00005    mov r0, #5
   8:   ebfffffe    bl  0 <more_fun>
   c:   e2800001    add r0, r0, #1
  10:   e8bd8010    pop {r4, pc}