编译并连接从helloworld.c生成的汇编代码的方法步骤
最近在学堂在线上重温汇编语言课程,整理了用gcc将helloworld.c程序生成汇编代码,并将汇编代码进行编译和连接生成可执行ELF文件的过程。方法和操作步骤记录如下以做备忘,同时也供各位感兴趣的同学学习参考。 整个过程是在ubuntu1604下进行的。(uname -srvio: Linux 4.4.0-83-generic #106-Ubuntu SMP Mon Jun 26 17
·
最近在学堂在线上重温汇编语言课程,整理了用gcc将helloworld.c程序生成汇编代码,并将汇编代码进行编译和连接生成可执行ELF文件的过程。方法和操作步骤记录如下以做备忘,同时也供各位感兴趣的同学学习参考。
整个过程是在ubuntu1604下进行的。(uname -srvio: Linux 4.4.0-83-generic #106-Ubuntu SMP Mon Jun 26 17:54:43 UTC 2017 x86_64 GNU/Linux)
0. 用c编写hello world程序helloworld.c
helloworld.c内容如下:
---------------
#include <stdlib.h>
#include <stdio.h>
int add(int x, int y) {
return x + y;
}
void main() {
char *msg = "hello world \n";
printf("%s", msg);
int x = 12;
int y = 8;
printf("%d + %d = %d \n", x, y, add(x, y));
return;
}
--------
1. 通过gcc -S 命令输出asm源文件helloworld64.s
$ gcc -S helloworld.c -o helloworld64.s
helloworld64.s
--------------
.file "helloworld.c" .text .globl add .type add, @function add: .LFB2: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -4(%rbp) movl %esi, -8(%rbp) movl -4(%rbp), %edx movl -8(%rbp), %eax addl %edx, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE2: .size add, .-add .section .rodata .LC0: .string "hello world \n" .LC1: .string "%s" .LC2: .string "%d + %d = %d \n" .text .globl main .type main, @function main: .LFB3: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp movq $.LC0, -8(%rbp) movq -8(%rbp), %rax movq %rax, %rsi movl $.LC1, %edi movl $0, %eax call printf movl $12, -16(%rbp) movl $8, -12(%rbp) movl -12(%rbp), %edx movl -16(%rbp), %eax movl %edx, %esi movl %eax, %edi call add movl %eax, %ecx movl -12(%rbp), %edx movl -16(%rbp), %eax movl %eax, %esi movl $.LC2, %edi movl $0, %eax call printf nop leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE3: .size main, .-main .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609" .section .note.GNU-stack,"",@progbits
------------
2. 通过as命令编译成目标文件helloworld64.o
$ as helloworld64.s -o helloworld64.o
3. 通过ld命令进行连接,生成可执行文件helloworld64
$ ld -m elf_x86_64 -dynamic-linker /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 "helloworld64.o" /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o /usr/lib/gcc/x86_64-linux-gnu/5/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o -lc -o "helloworld64"
注:除需连接libc库(-lc)外,还需链接c的运行时库crt*。如果版本不一样,可通过locate命令查找到相应的库文件,并把目录替换。如果不指定连接crt库,如$ ld -o helloworld64 helloworld64.o -lc 则会报以下错误:
ld: 警告: 无法找到项目符号 _start; 缺省为 0000000000400270
这是因为编译程序的默认起始执行地址(启动函数)为_start,此函数的crt库中。虽然可以通过-e选项进行修改,但c库的初始化等都需要crt中先执行。
4.执行helloworld64
$ ./helloworld64
输出结果如下:
输出结果如下:
-----
hello world
12 + 8 = 20
-----
对于在64位系统下生成32位程序,需指定32参数,并安装32位的库
$ sudo apt-get install g++-multilib
$ sudo apt-get install g++-multilib
1. 通过gcc -S 命令输出asm源文件helloworld32.s,使用-m32选项指示生成32位asm代码
$ gcc -m32 -S helloworld.c -o helloworld32.s
生成的
helloworld32.s内容如下:
-----
-----
.file "helloworld.c" .text .globl add .type add, @function add: .LFB2: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 movl 8(%ebp), %edx movl 12(%ebp), %eax addl %edx, %eax popl %ebp .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE2: .size add, .-add .section .rodata .LC0: .string "hello world \n" .LC1: .string "%s" .LC2: .string "%d + %d = %d \n" .text .globl main .type main, @function main: .LFB3: .cfi_startproc leal 4(%esp), %ecx .cfi_def_cfa 1, 0 andl $-16, %esp pushl -4(%ecx) pushl %ebp .cfi_escape 0x10,0x5,0x2,0x75,0 movl %esp, %ebp pushl %ecx .cfi_escape 0xf,0x3,0x75,0x7c,0x6 subl $20, %esp movl $.LC0, -20(%ebp) subl $8, %esp pushl -20(%ebp) pushl $.LC1 call printf addl $16, %esp movl $12, -16(%ebp) movl $8, -12(%ebp) subl $8, %esp pushl -12(%ebp) pushl -16(%ebp) call add addl $16, %esp pushl %eax pushl -12(%ebp) pushl -16(%ebp) pushl $.LC2 call printf addl $16, %esp nop movl -4(%ebp), %ecx .cfi_def_cfa 1, 0 leave .cfi_restore 5 leal -4(%ecx), %esp .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE3: .size main, .-main .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609" .section .note.GNU-stack,"",@progbits
-----
2. 通过as命令编译成目标文件helloworld32.o,通过--32选项指定32位模式
$ as --32 helloworld32.s -o helloworld32.o
3. 通过ld命令进行连接,生成可执行文件helloworld32,使用-melf_i386指定生成32位ELF可执行文件,并连接32位的crt运行时库等。
$ ld -melf_i386 -dynamic-linker /lib32/ld-linux.so.2 "helloworld32.o" /usr/lib32/crt1.o /usr/lib32/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/32/crtbegin.o /usr/lib/gcc/x86_64-linux-gnu/5/32/crtend.o /usr/lib32/crtn.o -lc -o "helloworld32"
注:除需连接libc库(-lc)外,还需链接c的运行时库crt*。如果版本不一样,可通过locate命令查找到相应的库文件,并把目录替换。
4.执行helloworld32
$ ./helloworld32
输出结果如下:
输出结果如下:
-----
hello world
12 + 8 = 20
更多推荐
已为社区贡献1条内容
所有评论(0)