将 C 程序转换为汇编
本文将讨论将 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)编写的源代码转换为机器可执行代码所涉及的步骤。 通常,在两者之间执行以下步骤:
- 预处理 - 预处理器程序执行三项任务。 第一个任务是包含头文件,第二个任务是替换宏,第三个任务是去除源程序中的注释
- 编译器——第二步,编译器将高级语言程序翻译成汇编语言程序
- 汇编程序——在第三步中,汇编程序采用汇编语言程序(由编译器翻译)并将其汇编成称为目标代码的机器可执行形式
- 链接器 - 在第四步中,链接器程序将已编译的库文件与目标代码附加在一起,以独立运行该程序
将 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
...
输出略有不同; mov
和 add
命令非常清楚。
反汇编目标代码
除了将 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
在此输出中,左侧的代码是十六进制的二进制代码。 在右侧,可以看到可读形式的汇编语言代码。
相关文章
在 C 语言中使用 typedef enum
发布时间:2023/05/07 浏览次数:181 分类:C语言
-
本文介绍了如何在 C 语言中使用 typedef enum。使用 enum 在 C 语言中定义命名整数常量 enum 关键字定义了一种叫做枚举的特殊类型。
C 语言中的 extern 关键字
发布时间:2023/05/07 浏览次数:114 分类:C语言
-
本文介绍了如何在 C 语言中使用 extern 关键字。C 语言中使用 extern 关键字来声明一个在其他文件中定义的变量
C 语言中的 #ifndef
发布时间:2023/05/07 浏览次数:186 分类:C语言
-
本文介绍了如何在 C 语言中使用 ifndef。在 C 语言中使用 ifndef 保护头文件不被多次包含 C 语言中的头文件用于定义同名源文件中实现的函数的接口。