首页 > 解决方案 > 难以理解编译器和汇编语言是如何组合在一起的

问题描述

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

https://www.tutorialspoint.com/embedded_systems/es_tools.htm

该网页讨论了编译器、汇编器和耦合。

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

标签: assembly

解决方案


使用 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 程序不是编译器,它是一个调用其他程序的程序。编译器输出是汇编语言

    .arch armv5t
    .fpu softvfp
    .eabi_attribute 20, 1
    .eabi_attribute 21, 1
    .eabi_attribute 23, 3
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 2
    .eabi_attribute 30, 2
    .eabi_attribute 34, 0
    .eabi_attribute 18, 4
    .file   "so.c"
    .text
    .align  2
    .global fun
    .syntax unified
    .arm
    .type   fun, %function
fun:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    push    {r4, lr}
    mov r0, #5
    bl  more_fun
    add r0, r0, #1
    pop {r4, pc}
    .size   fun, .-fun
    .ident  "GCC: (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609"
    .section    .note.GNU-stack,"",%progbits

然后 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}

中间的 bl 0 对 more_fun 函数的调用没有解析,因为该代码不是原始 C 源文件的一部分,因此在其中放置了一个占位符,链接器稍后会出现并将对象链接在一起。如果你不指定 -c 那么 gcc 也会为你调用链接器。

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

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

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


推荐阅读