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 <option(s)> <file(s)>
Display information from object <file(s)>.
At least one of the following switches must be given:
-a, --archive-headers Display archive header information
-f, --file-headers Display the contents of the overall file header
-p, --private-headers Display object format specific file header contents
-P, --private=OPT,OPT... Display object format specific contents
-h, --[section-]headers Display the contents of the section headers
-x, --all-headers Display the contents of all headers
-d, --disassemble Display assembler contents of executable sections
-D, --disassemble-all Display assembler contents of all sections
-S, --source Intermix source code with disassembly
-s, --full-contents Display the full contents of all sections requested
-g, --debugging Display debug information in object file
-e, --debugging-tags Display debug information using ctags style
-G, --stabs Display (in raw form) any STABS info in the file
-W[lLiaprmfFsoRt] or
--dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
=frames-interp,=str,=loc,=Ranges,=pubtypes,
=gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
=addr,=cu_index]
Display DWARF info in the file
-t, --syms Display the contents of the symbol table(s)
-T, --dynamic-syms Display the contents of the dynamic symbol table
-r, --reloc Display the relocation entries in the file
-R, --dynamic-reloc Display the dynamic relocation entries in the file
@<file> Read options from <file>
-v, --version Display this program's version number
-i, --info List object formats and architectures supported
-H, --help Display this information
The following switches are optional:
-b, --target=BFDNAME Specify the target object format as BFDNAME
-m, --architecture=MACHINE Specify the target architecture as MACHINE
-j, --section=NAME Only display information for section NAME
-M, --disassembler-options=OPT Pass text OPT on to the disassembler
-EB --endian=big Assume big endian format when disassembling
-EL --endian=little Assume little endian format when disassembling
--file-start-context Include context from start of file (with -S)
-I, --include=DIR Add DIR to search list for source files
-l, --line-numbers Include line numbers and filenames in output
-F, --file-offsets Include file offsets when displaying information
-C, --demangle[=STYLE] Decode mangled/processed symbol names
The STYLE, if specified, can be `auto', `gnu',
`lucid', `arm', `hp', `edg', `gnu-v3', `java'
or `gnat'
-w, --wide Format output for more than 80 columns
-z, --disassemble-zeroes Do not skip blocks of zeroes when disassembling
--start-address=ADDR Only process data whose address is >= ADDR
--stop-address=ADDR Only process data whose address is <= ADDR
--prefix-addresses Print complete address alongside disassembly
--[no-]show-raw-insn Display hex alongside symbolic disassembly
--insn-width=WIDTH Display WIDTH bytes on a single line for -d
--adjust-vma=OFFSET Add OFFSET to all displayed section addresses
--special-syms Include special symbols in symbol dumps
--prefix=PREFIX Add PREFIX to absolute paths for -S
--prefix-strip=LEVEL Strip initial directory names for -S
--dwarf-depth=N Do not display DIEs at depth N or greater
--dwarf-start=N Display DIEs starting with N, at the same depth
or deeper
--dwarf-check Make additional dwarf internal consistency checks.
objdump: supported targets: elf64-x86-64 elf32-i386 elf32-iamcu elf32-x86-64 a.out-i386-linux pei-i386 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big pe-x86-64 pe-bigobj-x86-64 pe-i386 plugin srec symbolsrec verilog tekhex binary ihex
objdump: supported architectures: i386 i386:x86-64 i386:x64-32 i8086 i386:intel i386:x86-64:intel i386:x64-32:intel i386:nacl i386:x86-64:nacl i386:x64-32:nacl iamcu iamcu:intel l1om l1om:intel k1om k1om:intel plugin
The following i386/x86-64 specific disassembler options are supported for use
with the -M switch (multiple options should be separated by commas):
x86-64 Disassemble in 64bit mode
i386 Disassemble in 32bit mode
i8086 Disassemble in 16bit mode
att Display instruction in AT&T syntax
intel Display instruction in Intel syntax
att-mnemonic
Display instruction in AT&T mnemonic
intel-mnemonic
Display instruction in Intel mnemonic
addr64 Assume 64bit address size
addr32 Assume 32bit address size
addr16 Assume 16bit address size
data32 Assume 32bit data size
data16 Assume 16bit data size
suffix Always display instruction suffix in AT&T syntax
amd64 Display instruction in AMD64 ISA
intel64 Display instruction in Intel64 ISA
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<stdio.h>
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 <main>:
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 <main+0xe>
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<stdio.h>
#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 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 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]
网友评论