迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > C语言 >

将 C 程序转换为汇编

作者:迹忆客 最近更新:2023/03/28 浏览次数:

本文将讨论将 C 语言程序转换为汇编语言代码。

我们将简要讨论汇编语言和 C 语言的基础知识。 稍后,我们将看到 C 程序到汇编代码的转换以及汇编代码的反汇编。


汇编语言

汇编是一种低级解释语言。 通常,用汇编语言编写的语句被翻译成单个机器级指令。

但是,它比机器语言更具可读性,因为它使用助记符。 助记符是类英文的指令或操作码。

例如,助记符 ADD 用于将两个数字相加。 同样,MOV 用于执行数据移动。

同样,CMP 比较两个表达式,而 JMP 将执行控制跳转到某个特定的标签或位置标记。

汇编语言非常接近机器(硬件); 因此,用汇编语言编写的指令非常快。 然而,程序员需要比高级语言的开发人员拥有更多的硬件知识。

汇编语言通常用于编写高效的系统程序,如设备驱动程序、病毒/反病毒程序、嵌入式系统软件和 TSR(终止和驻留程序)。

汇编程序必须将汇编语言程序汇编成机器上可执行的机器语言程序。


C语言

C 是一种与机器无关的高级编程语言。 通常,C 程序不需要硬件知识(只需要一点知识)。

C有高级语句,需要编译程序将C语言的每条语句翻译成一条或多条汇编语言语句。 例如,C语言中的一条简单指令 c = a + b ,被翻译成如下汇编语言语句:

mov edx, DWORD PTR -12[rbp]
mov eax, DWORD PTR -8[rbp]
add eax, edx
mov DWORD PTR -4[rbp], eax

在这里,在第一条和第二条语句中,内存中变量的值被移动到寄存器中。 添加指令将两个寄存器值相加。

在第四条语句中,寄存器中的值被移动到内存中的一个变量中。

此外,编译器要做很多工作,但程序员的生活很简单,在 C 语言中工作。 C 语言具有广泛的应用范围,从高级业务应用程序到低级实用程序。


将 C 程序转换为汇编语言

通常,人们使用复杂的集成环境来编写、编辑、编译、运行、修改和调试C语言程序,或者使用gcc命令将C语言程序转换为可执行程序。

这些工具使用户不知道将用某些高级语言(如 C)编写的源代码转换为机器可执行代码所涉及的步骤。 通常,在两者之间执行以下步骤:

  1. 预处理 - 预处理器程序执行三项任务。 第一个任务是包含头文件,第二个任务是替换宏,第三个任务是去除源程序中的注释
  2. 编译器——第二步,编译器将高级语言程序翻译成汇编语言程序
  3. 汇编程序——在第三步中,汇编程序采用汇编语言程序(由编译器翻译)并将其汇编成称为目标代码的机器可执行形式
  4. 链接器 - 在第四步中,链接器程序将已编译的库文件与目标代码附加在一起,以独立运行该程序

将 C 代码转换为等效程序集的命令

通常,命令行用户键入 gcc program_name.c ,它会生成一个可执行文件(如果没有错误)。 如果未给出目标文件名,则它在 UNIX 操作系统系列中可用 a.out 或在 Windows 操作系统中使用 program_name.exe

尽管如此,gcc 命令有一个庞大的参数列表来执行特定任务。 本教程将仅讨论 -s-C 标志。

-S 标志从 C 源代码生成汇编语言程序。 让我们使用以下示例来理解此标志,其中我们将 test.c 作为源文件:

//test.c
int main(){
    int a = 2, b = 3, c;
    c = a + b;
    return 0;
}

以下命令将生成扩展名为 .S 的目标汇编语言代码:

$ gcc -S test.c
$ ls
test.c test.s

该命令尚未创建机器语言代码; 仅生成汇编语言代码。 让我们在 Bash 中使用 cat 命令显示生成的汇编代码的内容:

$ cat test.s
    .file   "Test.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    endbr64
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $2, -12(%rbp)
    movl    $3, -8(%rbp)
    movl    -12(%rbp), %edx
    movl    -8(%rbp), %eax
    addl    %edx, %eax
    movl    %eax, -4(%rbp)
    ...

许多有为 Intel x86 架构编写汇编代码经验的程序员可能并不熟悉生成的汇编代码。

如果我们想要 Intel x86 架构的目标汇编代码,下面的命令将为我们做这件事:

$ gcc -S -masm=intel  Test.c

同样,输出将在 Test.s 文件中生成,可以在 Bash 终端中使用 cat 命令查看该文件。 在 Windows 中,我们可以在一些编辑器中打开它,例如记事本或更好的编辑器。

不管怎样,让我们看看上面命令生成的汇编代码的内容:

 cat Test.s
    .file   "Test.c"
    .intel_syntax noprefix
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    endbr64
    push    rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    mov rbp, rsp
    .cfi_def_cfa_register 6
    mov DWORD PTR -12[rbp], 2
    mov DWORD PTR -8[rbp], 3
    mov edx, DWORD PTR -12[rbp]
    mov eax, DWORD PTR -8[rbp]
    add eax, edx
    mov DWORD PTR -4[rbp], eax
    ...

输出略有不同; movadd 命令非常清楚。

反汇编目标代码

除了将 C 语言程序转换为汇编语言外,人们可能还想反汇编二进制代码(机器代码)以查看等效的汇编语言代码。 我们可以使用 Linux 中的 objdump 实用程序来做到这一点。

例子:

假设我们在 Bash 终端执行 gcc -c Test.c 命令来编译 Test.c 文件。 它创建一个名为 Test.o 的目标文件(机器语言代码)。

现在,如果我们想看到将此目标代码重新转换/反汇编为等效的汇编代码,我们可以使用以下 Bash 命令来实现:

$ objdump -d Test.o

Test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:   f3 0f 1e fa             endbr64
   4:   55                      push   %rbp
   5   48 89 e5                 mov    %rsp,%rbp
   8:   c7 45 f4 02 00 00 00    movl   $0x2,-0xc(%rbp)
   f:   c7 45 f8 03 00 00 00    movl   $0x3,-0x8(%rbp)
  16:   8b 55 f4                mov    -0xc(%rbp),%edx
  19:   8b 45 f8                mov    -0x8(%rbp),%eax
  1c:   01 d0                   add    %edx,%eax
  1e:   89 45 fc                mov    %eax,-0x4(%rbp)
  21:   b8 00 00 00 00          mov    $0x0,%eax
  26:   5d                      pop    %rbp

在此输出中,左侧的代码是十六进制的二进制代码。 在右侧,可以看到可读形式的汇编语言代码。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

在 C 语言中使用 typedef enum

发布时间:2023/05/07 浏览次数:181 分类:C语言

本文介绍了如何在 C 语言中使用 typedef enum。使用 enum 在 C 语言中定义命名整数常量 enum 关键字定义了一种叫做枚举的特殊类型。

C 语言中的静态变量

发布时间:2023/05/07 浏览次数:151 分类:C语言

本文介绍了如何在 C 语言中使用静态变量。在 C 语言中使用 static 变量在函数调用之间保存变量值

C 语言中生成随机数

发布时间:2023/05/07 浏览次数:64 分类:C语言

本文演示了如何在 C 语言中生成随机数。使用 rand 和 srand 函数在 C 语言中生成随机数

C 语言中的 i++ 与++i

发布时间:2023/05/07 浏览次数:83 分类:C语言

本文演示了如何在 C 语言中使用前缀增量与后缀增量运算符。C 语言中++i 和 i++ 记号的主要区别

C 语言中获取当前工作目录

发布时间:2023/05/07 浏览次数:182 分类:C语言

本文演示了如何在 C 语言中获取当前工作目录。使用 getcwd 函数获取当前工作目录的方法

C 语言中的位掩码

发布时间:2023/05/07 浏览次数:126 分类:C语言

本文介绍了如何在 C 语言中使用位掩码。使用 struct 关键字在 C 语言中定义位掩码数据

C 语言中的排序函数

发布时间:2023/05/07 浏览次数:181 分类:C语言

本文演示了如何在 C 语言中使用标准库排序函数。使用 qsort 函数对 C 语言中的整数数组进行排序

C 语言中的 extern 关键字

发布时间:2023/05/07 浏览次数:114 分类:C语言

本文介绍了如何在 C 语言中使用 extern 关键字。C 语言中使用 extern 关键字来声明一个在其他文件中定义的变量

C 语言中的 #ifndef

发布时间:2023/05/07 浏览次数:186 分类:C语言

本文介绍了如何在 C 语言中使用 ifndef。在 C 语言中使用 ifndef 保护头文件不被多次包含 C 语言中的头文件用于定义同名源文件中实现的函数的接口。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便