vim exit.s
# 以#开始的行为注释行,汇编程序不会对注释做任何处理
# %eax保存系统调用号
# %ebx保存返回状态
.section .data #.section为汇编指令或伪操作,由汇编程序处理,它将程序分为几个部分
#.data指令是数据段的开始,数据段中要列出程序所需的所有内存存储空间
.section .text #.text是程序文本段的开始,即存放程序指令的部分
.globl _start #.globl表示汇编程序不应在汇编之后废弃此符号,因为链接器要用到它
#_start 很重要,_start 是一个符号,这就说在它将在汇编和链接过程中被其它内容替换掉
#符合一般用来标记程序或数据的内存位置
#_start 是一个特殊符号,标记了程序的开始位置
_start:
#_start:定义一个标签,标签是一个符合,后面跟一个冒号,定义一个符合的值
movl $1, %eax #这是用于退出程序的Linux内核系统调用号
movl $0, %ebx #这是程序将返回给os的状态码
#改变这个数字,则返回到echo $?的值不同
int $0x80 #这将唤醒内核,以运行退出命令
运行汇编程序,exit.o称为目标文件,每个源文件转换为一个目标文件。
as exit.s -o exit.o
有一类称为反汇编器(disassembler)的程序,将根据机器代码产生汇编代码,Linux中带-d命令的objdump(object dump)可以充当这个角色。
Usage: objdump
objdump -d exit.o
exit.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <_start>:
0: b8 01 00 00 00 mov $0x1,%eax
5: bb 00 00 00 00 mov $0x0,%ebx
a: cd 80 int $0x80
接下来,使用链接器将多个目标文件合二为一,并添加必要的信息,使内核能够加载和运行该程序。
ld exit.o -o exit
ll
-rwxrwxr-x 1 sun sun 664 4月 3 22:28 exit*
-rw-rw-r-- 1 sun sun 704 4月 3 22:24 exit.o
-rw-rw-r-- 1 sun sun 143 4月 3 22:23 exit.s
最后,运行exit,
./exit
sun@sun-virtual-machine:~/assembly0x$ ./exit
sun@sun-virtual-machine:~/assembly0x$ echo $?
0
gcc的使用和编译过程
gcc (GNU C Compiler -> GNU Compiler Collection)
gcc -v
root@vultr:~/clang# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.11' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)
root@vultr:~/clang#
gcc -o 输出文件名 输入文件名
root@vultr:~/clang# vi 001.c
root@vultr:~/clang# gcc -o 001 001.c
root@vultr:~/clang# ls
001 001.c
root@vultr:~/clang# ./001
Hello World!
root@vultr:~/clang#
#include
int main(){
printf("Hello World!\n");
return 0;
}
gcc -v -o 输出文件名 输入文件名
root@vultr:~/clang# gcc -v -o 001 001.c
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.11' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)
COLLECT_GCC_OPTIONS='-v' '-o' '001' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/5/cc1 -quiet -v -imultiarch x86_64-linux-gnu 001.c -quiet -dumpbase 001.c -mtune=generic -march=x86-64 -auxbase 001 -version -fstack-protector-strong -Wformat -Wformat-security -o /tmp/ccRDp47M.s
GNU C11 (Ubuntu 5.4.0-6ubuntu1~16.04.11) version 5.4.0 20160609 (x86_64-linux-gnu)
compiled by GNU C version 5.4.0 20160609, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3
GGC heuristics: --param ggc-min-expand=97 --param ggc-min-heapsize=126976
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/5/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/5/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
GNU C11 (Ubuntu 5.4.0-6ubuntu1~16.04.11) version 5.4.0 20160609 (x86_64-linux-gnu)
compiled by GNU C version 5.4.0 20160609, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3
GGC heuristics: --param ggc-min-expand=97 --param ggc-min-heapsize=126976
Compiler executable checksum: 5f69ca549f086e2c3748f9d1423a4dee
COLLECT_GCC_OPTIONS='-v' '-o' '001' '-mtune=generic' '-march=x86-64'
as -v --64 -o /tmp/ccNWBljL.o /tmp/ccRDp47M.s
GNU assembler version 2.26.1 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.26.1
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/5/:/usr/lib/gcc/x86_64-linux-gnu/5/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/5/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/5/:/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/5/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/5/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' '001' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/5/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/5/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper -plugin-opt=-fresolution=/tmp/cczNUkwJ.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --sysroot=/ --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro -o 001 /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/5 -L/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/5/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/5/../../.. /tmp/ccNWBljL.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/5/crtend.o /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o
root@vultr:~/clang#
gcc编译过程
- 预处理
cpp -o xxx.i xxx.c
(cpp,生成预处理文件的命令)
等价于gcc -E
主要是:替换,处理那些源代码文件中以#
开头的预编译指令,比如#define
和#include
。处理所有条件编译指令#if、#elif、#else、#ifdef、#ifndef、#endif
所以define
和include
到了编译阶段就没有了,因此也不是关键字
。 - 编译
/usr/lib/gcc/x86_64-linux-gnu/5/cc1
(cc1包含了预处理和编译)
/usr/lib/gcc/x86_64-linux-gnu/5/cc1 001.c -o /tmp/ccRDp47M.s
上述命令等价于gcc -S output input
- 汇编
as -v --64 -o /tmp/ccNWBljL.o /tmp/ccRDp47M.s
编译到此步骤的命令gcc -c
- 链接
/usr/lib/gcc/x86_64-linux-gnu/5/collect2 -o 001 /tmp/ccNWBljL.o
+....
编译到此步骤的命令gcc -o
例证:
1、生成汇编代码
root@vultr:~/clang# ls
001.c
root@vultr:~/clang# gcc -S -o 001.s 001.c
root@vultr:~/clang# ll
total 16
drwxr-xr-x 2 root root 4096 Apr 18 10:09 ./
drwx------ 5 root root 4096 Apr 18 09:19 ../
-rw-r--r-- 1 root root 70 Apr 18 09:12 001.c
-rw-r--r-- 1 root root 455 Apr 18 10:09 001.s
root@vultr:~/clang# vi 001.s
.file "001.c"
.section .rodata
.LC0:
.string "Hello World!"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
call puts
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits
2、生成目标文件
root@vultr:~/clang# ls
001.c 001.s
root@vultr:~/clang# gcc -c -o 001.o 001.s
root@vultr:~/clang# ll
total 20
drwxr-xr-x 2 root root 4096 Apr 18 10:21 ./
drwx------ 5 root root 4096 Apr 18 10:15 ../
-rw-r--r-- 1 root root 70 Apr 18 09:12 001.c
-rw-r--r-- 1 root root 1504 Apr 18 10:21 001.o
-rw-r--r-- 1 root root 455 Apr 18 10:09 001.s
root@vultr:~/clang# vi 001.o
目标文件,一堆乱码!
root@vultr:~/clang# rm 001.o
root@vultr:~/clang# ls
001.c 001.s
root@vultr:~/clang# gcc -c -o 001.o 001.c
root@vultr:~/clang# ls
001.c 001.o 001.s
root@vultr:~/clang# ll
total 20
drwxr-xr-x 2 root root 4096 Apr 18 10:23 ./
drwx------ 5 root root 4096 Apr 18 10:22 ../
-rw-r--r-- 1 root root 70 Apr 18 09:12 001.c
-rw-r--r-- 1 root root 1504 Apr 18 10:23 001.o
-rw-r--r-- 1 root root 455 Apr 18 10:09 001.s
root@vultr:~/clang#
下面来下反编译:
root@vultr:~/clang# ls
001.c 001.o 001.s
root@vultr:~/clang# objdump -d 001.o
001.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 :
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: bf 00 00 00 00 mov $0x0,%edi
9: e8 00 00 00 00 callq e
e: b8 00 00 00 00 mov $0x0,%eax
13: 5d pop %rbp
14: c3 retq
root@vultr:~/clang#
3、再看下.O目标文件链接生成可执行文件
root@vultr:~/clang# ls
001.c 001.o 001.s
root@vultr:~/clang# gcc -o 001 001.o
root@vultr:~/clang# ls
001 001.c 001.o 001.s
root@vultr:~/clang# ./001
Hello World!
root@vultr:~/clang#
4、关于预处理命令的例证
#include
#define NUM 10
int main(){
int a=NUM;
printf("Hello World!\n");
return 0;
}
root@vultr:~/clang# vim 001.c
root@vultr:~/clang# gcc -E -o 001.i 001.c
root@vultr:~/clang# ll
total 32
drwxr-xr-x 2 root root 4096 Apr 18 10:49 ./
drwx------ 5 root root 4096 Apr 18 10:49 ../
-rw-r--r-- 1 root root 97 Apr 18 10:48 001.c
-rw-r--r-- 1 root root 17105 Apr 18 10:49 001.i
root@vultr:~/clang# vim 001.i
# 1 "001.c"
# 1 ""
# 1 ""
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "" 2
# 1 "001.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 367 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 1 3 4
# 410 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 411 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
# 368 "/usr/include/features.h" 2 3 4
# 391 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 1 3 4
# 10 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4
# 392 "/usr/include/features.h" 2 3 4
# 28 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h" 1 3 4
# 216 "/usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h" 3 4
# 216 "/usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h" 3 4
typedef long unsigned int size_t;
# 34 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/types.h" 1 3 4
# 27 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 28 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
typedef unsigned char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
typedef unsigned long int __u_long;
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef signed short int __int16_t;
typedef unsigned short int __uint16_t;
typedef signed int __int32_t;
typedef unsigned int __uint32_t;
typedef signed long int __int64_t;
typedef unsigned long int __uint64_t;
typedef long int __quad_t;
typedef unsigned long int __u_quad_t;
# 121 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/typesizes.h" 1 3 4
# 122 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
typedef unsigned long int __dev_t;
typedef unsigned int __uid_t;
typedef unsigned int __gid_t;
typedef unsigned long int __ino_t;
typedef unsigned long int __ino64_t;
typedef unsigned int __mode_t;
typedef unsigned long int __nlink_t;
typedef long int __off_t;
typedef long int __off64_t;
typedef int __pid_t;
typedef struct { int __val[2]; } __fsid_t;
typedef long int __clock_t;
typedef unsigned long int __rlim_t;
typedef unsigned long int __rlim64_t;
typedef unsigned int __id_t;
#中间省略
# 942 "/usr/include/stdio.h" 3 4
# 2 "001.c" 2
# 3 "001.c"
int main(){
int a=10;
printf("Hello World!\n");
return 0;
}
[END]