0%

Shell笔记

本文记录了常用的shell笔记

基本使用

通配符

  • ?字符代表单个字符,?不能匹配空字符。
  • *代表任意数量的字符,可以匹配空字符。
  • [...]匹配方括号之中的任意一个字符,比如[aeiou]可以匹配五个元音字母。
1
2
3
4
5
6
7
8
9
10
11
12
# 假设当前目录下存在,文件 a.txt、b.txt、c.txt、ab.txt、report1.txt、report2.txt 和 report3.txt
$ ls ?.txt
a.txt b.txt c.txt

$ ls ??.txt
ab.txt

$ ls [ab].txt
a.txt b.txt

$ ls *[ab].txt
ab.txt a.txt b.txt
  • [start-end]表示一个连续的范围。
1
2
3
4
5
$ ls [a-c].txt
a.txt b.txt c.txt

$ ls report[0-9].txt
report1.txt report2.txt report3.txt
  • [^...][!...]表示匹配不在方括号里面的字符(不包括空字符)。这两种写法是等价的。这种模式下也可以使用连续范围的写法[!start-end]
1
2
3
4
5
$ ls [^a].txt
b.txt c.txt

$ ls report[!2-3].txt
report1.txt
  • {...} 表示匹配大括号里面的所有模式,模式之间使用逗号分隔。它可以用于多字符的模式。
1
2
3
4
5
$ echo d{a,e,i,u,o}g
dag deg dig dug dog

$ echo {cat,dog}
cat dog
  • {...}[...]有一个很重要的区别。如果匹配的文件不存在,[...]会失去模式的功能,变成一个单纯的字符串,而{...}依然可以展开。
1
2
3
4
5
6
7
# 不存在 a.txt 和 b.txt
$ ls [ab].txt
ls: [ab].txt: No such file or directory

$ ls {a,b}.txt
ls: a.txt: No such file or directory
ls: b.txt: No such file or directory
  • 大括号可以嵌套。
1
2
$ echo {j{p,pe}g,png}
jpg jpeg png
  • 大括号也可以与其他模式联用。
1
2
$ echo {cat,d*}
cat dawg dg dig dog doug dug
  • {start..end}会匹配连续范围的字符。如果遇到无法解释的扩展,模式会原样输出。
1
2
3
4
5
6
7
8
$ echo d{a..d}g
dag dbg dcg ddg

$ echo {11..15}
11 12 13 14 15

$ echo {a1..3c}
{a1..3c}

编译链接

ld

ld命令是二进制工具集GNU Binutils的一员,是GNU链接器,用于将目标文件与库链接为可执行程序或库文件。

ldd

ldconfig

查找搜索

find

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# find [path] -name []
$ find / -name hello[a-z].log

# 根据文件时间戳搜索
$ find / -type f -atime -7 # 搜索近七天内被访问过的所有文件

# 根据文件大小搜索
$ find . -type f -size +10k

# 删除匹配文件
$ find . type f -name "*.txt" -delete

# 搜索但跳过指定目录
$ find . -path "./sk" -prune -o -name "*.txt" # -o means logical OR

grep

ack

ag

1
2


磁盘和文件系统

fdisk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 列出块设备信息:以树形展示你的磁盘以及磁盘分区信息
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 931.5G 0 disk
└─sda1 8:1 0 931.5G 0 part /data
sdb 8:16 0 119.2G 0 disk
├─sdb1 8:17 0 512M 0 part /boot/efi
└─sdb2 8:18 0 118.8G 0 part /

# 检查文件系统的磁盘空间占用情况
$ df -Tlh
Filesystem Type Size Used Avail Use% Mounted on
tmpfs tmpfs 1.6G 1.9M 1.6G 1% /run
/dev/sdb2 ext4 117G 110G 613M 100% /
/dev/sdb1 vfat 511M 6.1M 505M 2% /boot/efi
/dev/sda1 ext4 916G 611G 260G 71% /data

# fdisk磁盘分区,分区有大小限制为2T
$ fdisk -l # 查看系统上的硬盘
Disk /dev/sda: 931.5 GiB, 1000204886016 bytes, 1953525168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 67A1E9ED-BCBF-44B4-93FD-8FA305437B2E

Device Start End Sectors Size Type
/dev/sda1 2048 1953525134 1953523087 931.5G Linux filesystem


Disk /dev/sdb: 119.2 GiB, 128035676160 bytes, 250069680 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 0AA99923-E2A0-4D46-9A95-71036FC86EEF

Device Start End Sectors Size Type
/dev/sdb1 2048 1050623 1048576 512M EFI System
/dev/sdb2 1050624 250068991 249018368 118.8G Linux filesystem

# parted磁盘分区,相对fdisk可以对更大的磁盘进行划分

mount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# mkfs [options] [-t <vfs-type>] <device>
mkfs -t ext4 /dev/sdc1

# mount
# mount [options] [device] [mount-point]
# -t vfstype 指定文件系统的类型
# -o options 主要用来描述设备或档案的挂接方式
# loop:用来把一个文件当成硬盘分区挂接上系统
# ro:采用只读方式挂接设备
# rw:采用读写方式挂接设备
# iocharset:指定访问文件系统所用字符集
mount -t ext4 /dev/sdc1 /mnt/lfs

# umount
umount /mnt/lfs

dd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 将本地的/dev/hdb整盘备份到/dev/hdd
$ dd if=/dev/hdb of=/dev/hdd
# 将/dev/hdb全盘数据备份到指定路径的image文件
$ dd if=/dev/hdb of=/root/image
# 将备份文件恢复到指定盘
$ dd if=/root/image of=/dev/hdb
# 备份/dev/hdb全盘数据,并利用gzip工具进行压缩,保存到指定路径
$ dd if=/dev/hdb | gzip > /root/image.gz
# 压缩的备份文件恢复到指定盘
$ gzip -dc /root/image.gz | dd of=/dev/hdb

# 备份与恢复MBR
## 备份磁盘开始的512个字节大小的MBR信息到指定文件:
$ dd if=/dev/hda of=/root/image count=1 bs=512 # count=1指仅拷贝一个块;bs=512指块大小为512个字节
## 恢复:
$ dd if=/root/image of=/dev/had # 将备份的MBR信息写到磁盘开始部分

# 拷贝内存内容到硬盘
$ dd if=/dev/mem of=/root/mem.bin bs=1024 (指定块大小为1k)
# 拷贝光盘内容到指定文件夹,并保存为cd.iso文件
$ dd if=/dev/cdrom(hdc) of=/root/cd.iso

# 增加swap分区文件大小
## 第一步:创建一个大小为256M的文件:
$ dd if=/dev/zero of=/swapfile bs=1024 count=262144
## 第二步:把这个文件变成swap文件:
$ mkswap /swapfile
## 第三步:启用这个swap文件:
$ swapon /swapfile
## 第四步:编辑/etc/fstab文件,使在每次开机时自动加载swap文件:
$ swapfile swap swap default 0 0

# 销毁磁盘数据
$ dd if=/dev/urandom of=/dev/hda1
# 注意:利用随机的数据填充硬盘,在某些必要的场合可以用来销毁数据。

# 测试硬盘的读写速度
$dd if=/dev/zero bs=1024 count=1000000 of=/root/1Gb.file
$ dd if=/root/1Gb.file bs=64k | dd of=/dev/null
# 通过以上两个命令输出的命令执行时间,可以计算出硬盘的读、写速度。

# 确定硬盘的最佳块大小:
$ dd if=/dev/zero bs=1024 count=1000000 of=/root/1Gb.file
$ dd if=/dev/zero bs=2048 count=500000 of=/root/1Gb.file
$ dd if=/dev/zero bs=4096 count=250000 of=/root/1Gb.file
$ dd if=/dev/zero bs=8192 count=125000 of=/root/1Gb.file
# 通过比较以上命令输出中所显示的命令执行时间,即可确定系统最佳的块大小。

# 修复硬盘:
$ dd if=/dev/sda of=/dev/sda
# 当硬盘较长时间(一年以上)放置不使用后,磁盘上会产生magnetic flux point,当磁头读到这些区域时会遇到困难,并可能导致I/O错误。当这种情况影响到硬盘的第一个扇区时,可能导致硬盘报废。上边的命令有可能使这些数据起死回生。并且这个过程是安全、高效的。

# 利用netcat远程备份
$ dd if=/dev/hda bs=16065b | netcat < targethost-IP > 1234
# 在源主机上执行此命令备份/dev/hda
$ netcat -l -p 1234 | dd of=/dev/hdc bs=16065b
# 在目的主机上执行此命令来接收数据并写入/dev/hdc
$ netcat -l -p 1234 | bzip2 > partition.img
$ netcat -l -p 1234 | gzip > partition.img
# 以上两条指令是目的主机指令的变化分别采用bzip2、gzip对数据进行压缩,并将备份文件保存在当前目录。

# 将一个很大的视频文件中的第i个字节的值改成0x41(也就是大写字母A的ASCII值)
$ echo A | dd of=bigfile seek=$i bs=1 count=1 conv=notrunc

设备管理

1
2
3
4
# mknod 创建块设备或者字符设备文件
# mknod [OPTION]... NAME TYPE [MAJOR MINOR]
$ mknod /dev/sdb4 b 1 1 # 创建一个块设备
$ mknod /dev/console5 c 5 1 # 创建一个字符设备

用户管理

1
2
3
4
5
# 增加用户
$ adduser houmin

# 把用户加到组
$ usermod -aG sudo houmin

软链接和硬链接

  • 硬链接:通过索引 inode来映射到文件数据。linux允许多个文件名指向同一 inode。删除硬链接并不会导致数据实体被删除,只有最后一个链接被删除,同时磁盘有新数据要存放时,才能导致数据实体删除。
  • 软链接:也称符号链接,类似于windows系统中的快捷方式,与硬链接不同,软链接就是一个普通文件,只是数据块内容有点特殊,文件用户数据块中存放的内容是另一文件的路径名的指向,通过这个方式可以快速定位到软连接所指向的源文件实体。
1
2
3
4
5
6
7
8
9
10
11
# 创建硬链接
ln [target] [link_name]

# 创建软链接
ln -s [target] [link_name]

# 修改软链接
ln -snf [new_target] [link_name]

# 删除软链接
rm -rf [link_name]

远程同步文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# scp: secure copy,用于远程的文件的复制
# -r 递归复制整个目录
scp [option] [source] [dest]

# rsync: remote sync, 用于数据镜像备份,可用于增量更新
# -a, --archive 归档模式,表示以递归方式传输文件,并保持所有文件属性,等于-rlptgoD
# -v, --verbose 详细模式输出
# -z, --compress 对备份的文件在传输时进行压缩处理
# -u 加上该选项后,如果DEST中的文件比SRC新,则不同步
# -P, --partial --progress 保留那些因故没有完全传输的文件,以是加快随后的再次传输
# --delete 删除DEST中SRC没有的文件
# --exclude 过滤指定文件,如--exclude “logs”会把文件名包含logs的文件或者目录过滤掉,不同步

# rsync [option] [source] [dest]
$ rsync -avP houmin@host1:~/data alice@host2:/data/

包管理工具

apt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# apt 命令就是 apt-get、apt-cache 和 apt-config 中最常用命令选项的集合
$ sudo apt update # 更新包索引文
$ sudo apt install nginx # 安装包
$ sudo apt install vim=2:8.0.1453-1ubuntu1 # 安装指定版本的包
$ sudo apt install name.deb # 安装本地的 deb 包文件

# 安装系统中有更新的包
$ sudo apt update
$ sudo apt upgrade

# 删除包
# 其中 remove 命令会保留配置文件,而 purge 命令会把配置文件一起删除
$ sudo apt remove nmap
$ sudo apt purge nmap

# 查看包的信息
$ apt show vim

# 输出指定条件的包列表
$ apt list vim*

# 搜索包
$ apt search docker

压缩解压

tar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 解压
$ tar -xf file.tar # 解压 tar包
$ tar -xzf file.tar.gz # 解压tar.gz
$ tar -xjf file.tar.bz2 # 解压 tar.bz2
$ tar -xJf file.tar.xz # 解压 tar.xz
$ tar -xZf file.tar.Z # 解压tar.Z
$ unrar e file.rar # 解压rar
$ unzip file.zip # 解压zip

# 压缩
$ tar -cvf jpg.tar *.jpg
$ tar -czf jpg.tar.gz *.jpg
$ tar -cjf jpg.tar.bz2 *.jpg
$ tar -cZf jpg.tar.Z *.jpg
$ rar a jpg.rar *.jpg
$ zip jpg.zip *.jpg

cpio

cpio是一个非常古老的归档工具,已逐渐被tar替代,但是有些功能是tar不存在的,所以还是分享下它的用法。

cpio用于创建、解压归档文件,也可以对归档文件执行拷入拷出的动作,即向归档文件中追加文件,或从归档文件中提取文件。它也支持tar格式的归档文件,但是对压缩后的tar(如.tar.gz格式)就没法支持了,cpio毕竟不会调用对应的(解)压缩工具。

cpio一般从标准输入获取数据,写入到标准输出,所以一般会结合管道、输入重定向、输出重定向使用。命令格式如下

1
2
3
$ cpio –o [abcv]
$ cpio –i [bcdmrtuv] [patterns]
$ cpio –p [adlmuv] [directory]

对应上述三种命令,cpio有三种运行模式:

  • Copy-out模式

    此模式下,cpio将向归档文件中拷入文件,即进行归档操作,所以称为归档模式。它会从标准输入中读取待归档的文件,将它们归档到目标目标中,若未指定归档的目标,将归档到标准输出中。

  • Copy-in模式

    此模式下,cpio将从归档文件中提取文件,或者列出归档文件中的文件列表。它将从标准输入中读取归档文件。

  • Copy-pass模式

    此模式下,从一个目录向另一个目录或从一个文件系统向另一个文件系统复制文件,合并copy-out和copy-in命令的功能。

上面命令的选项如下:

1
2
3
4
5
6
7
8
-o 将文件拷贝打包成文件或者将文件输出到设备上。
-i 将打包文件解压或者将设备上的备份还原到系统。
-t 查看cpio打包的文件内容或者输出到设备上的文件内容。
-v 显示打包过程中的文件名称。
-d 在cpio还原文件的过程中,自动的建立相应的目录。
-c Use the old POSIX portable character format
-B 让默认的Blocks可以增大到5120 bytes,默认Blocks为512 bytes,这样做的好处是可以加快存取速度。
-H Produce the output archive in the specified format.

下面是 cpio 的常见使用案例:

1
2
3
4
5
6
# 将etc目录备份
$ find ./etc -print | cpio -ov > etc.cpio
# 恢复文件
$ cpio -idv < /root/etc.cpio
# 只是查看etc.cpio文件
$ cpio -tv < etc.cpio

定时任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# crontab

# crontab 文件含义
# minute hour day month week command
# 30 21 * * * /etc/init.d/smb restart # 每晚的21:30重启smb
# * */1 * * * /etc/init.d/smb restart # 每一小时重启smb
# 0,15,30,45 18-06 * * * /bin/echo `date` > dev/tty1 # 每天的18点到6点的每隔15分钟执行

# 编辑 crontab 文件
$ crontab -e

# 列出 crontab 文件
$ crontab -l
0,15,30,45 18-06 * * * /bin/echo `date` > dev/tty1

bash_profile 和 bashrc

进阶使用

xargs

xargs命令的作用,是将标准输入转为命令行参数。大多数命令(比如rm, mkdir,ls) 与管道一起使用时,都需要 xargs 将标准输入专为命令行参数。关于 xargs与管道的区别,可以参考这篇文章

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 其命令格式如下
$ xargs [-options] [command]
$ find . -name "*.txt" | xargs grep "abc"

# -d 参数可定制分隔符
$ echo -e "a\tb\tc" | xargs -d "\t" echo
a b c

# -I指定每一项命令行参数的替代字符串
$ cat foo.txt
one
two
three

$ cat foo.txt | xargs -I file sh -c 'echo file; mkdir file'

$ ls
one two three

# xargs默认只用一个进程执行命令,--max-procs 参数指定同时用多少个进程并行执行命令,0 表示不限制
$ docker ps -q | xargs -n 1 --max-procs 0 docker kill

parallel

watch

tmux

1
2


chroot

chroot,即 change root directory (更改 root 目录)。在 linux 系统中,系统默认的目录结构都是以 /,即以根 (root) 开始的。而在使用 chroot 之后,系统的目录结构将以指定的位置作为 / 位置。

1
# chroot [options] NEWROOT [COMMANDS]
  • 增加了系统的安全性,限制了用户的权力:

在经过 chroot 之后,在新根下将访问不到旧系统的根目录结构和文件,这样就增强了系统的安全性。这个一般是在登录 (login) 前使用 chroot,以此达到用户不能访问一些特定的文件。

  • 建立一个与原系统隔离的系统目录结构,方便用户的开发:

使用 chroot 后,系统读取的是新根下的目录和文件,这是一个与原系统根下文件不相关的目录结构。在这个新的环境中,可以用来测试软件的静态编译以及一些与系统不相关的独立开发。

  • 切换系统的根目录位置,引导 Linux 系统启动以及急救系统等:

chroot 的作用就是切换系统的根位置,而这个作用最为明显的是在系统初始引导磁盘的处理过程中使用,从初始 RAM 磁盘 (initrd) 切换系统的根位置并执行真正的 init。另外,当系统出现一些问题时,我们也可以使用 chroot 来切换到一个临时的系统。

编写脚本

set -x

source 的区别

文本处理

awk

sed

系统调试

查看进程

1
2
3
4
5
# -p: 同时显示每个进程的 PID
# -u: 同时列出每个进程所属账号名称
$ pstree -up

$ ps -aux

杀死进程

1
2
$ pgrep [进程名] # 等同于 ps aux | grep [进程名]
$ pkill [进程名] # 等同于 pgrep [进程名] | xargs kill -9

查看网络端口

netstat 是一款命令行工具,可用于列出系统上所有的网络套接字连接情况,包括 tcp, udp 以及 unix 套接字,另外它还能列出处于监听状态(即等待接入请求)的套接字,参考这篇文章

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# netstat 参数
# -t 列出TCP协议的连接,-u 列出UDP协议的连接
# -n 禁用域名解析,只列出IP地址,可提升查找速度
# -l 列出正在监听的套接字
# -p 查看进程信息

# 列出正在监听中的连接
$ sudo netstat -lntp
$ netstat -lntp

# 打印 active 状态的连接
$ netstat -atnp | grep ESTA
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 0 192.168.1.2:49156 173.255.230.5:80 ESTABLISHED 1691/chrome
tcp 0 0 192.168.1.2:33324 173.194.36.117:443 ESTABLISHED 1691/chrome

查看打开文件

lsof(list open files)是一个列出当前系统打开文件的工具。在linux环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件。

1
2
3
4
5
6
7
$ lsof -i # 列出所有的网络的连接
$ lsof -i tcp # 列出所有TCP连接
$ lsof -i :3306 # 列出谁在使用某个端口
$ lsof -i udp:80 # 列出谁在使用某个特定的UDP端口
$ lsof -p 234 # 列出进程234打开的所有文件
$ lsof -u houmin #列出用户houmin打开的所有文件
$ lsof -c mysql # 列出所有以mysql这个进程开头的程序的文件

查看磁盘占用

任务管理器 top

top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
top - 16:27:05 up 157 days, 18:43,  6 users,  load average: 0.00, 0.00, 0.00
Tasks: 121 total, 2 running, 119 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.0 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 2048028 total, 340732 free, 198124 used, 1509172 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 1631636 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
10109 root 10 -10 132768 17288 14768 S 0.3 0.8 8:55.79 AliYunDun
12503 houmin 20 0 42720 16312 2764 S 0.3 0.8 0:41.47 tmux
1 root 20 0 119584 5224 3468 S 0.0 0.3 1:02.52 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:30.96 ksoftirqd/0
5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
7 root 20 0 0 0 0 R 0.0 0.0 14:00.55 rcu_sched
8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh
9 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
10 root rt 0 0 0 0 S 0.0 0.0 0:41.19 watchdog/0
11 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs

关于 top 的显示的具体意义,可以参考 To be done

跟踪进程中的系统调用 strace

跟踪进程栈 ptrack

监视内存使用 vmstat

监视 I/O子系统 iostat/iotop/dstat

找出系统瓶颈 sar

查看程序依赖库 ldd

1
2
3
4
5
6
7
8
9
10
11
12
13
# ldd: list dynamic dependencies, 用于查看动态库的依赖关系
# ldd 常用来解决程式因缺少某个库文件而不能运行的一些问题。
$ ldd /bin/ls
linux-vdso.so.1 => (0x00007ffe25deb000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f8e79815000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8e7944b000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f8e791db000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f8e78fd7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8e79a37000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8e78dba000)
# 第一列:程序需要依赖什么库
# 第二列: 系统提供的与程序需要的库所对应的库
# 第三列:库加载的开始地址

原理: ldd不是个可执行程式,而只是个shell脚本; ldd显示可执行模块的dependency的工作原理,其实质是通过 ld-linux.so(elf动态库的装载器)来实现的。ld-linux.so模块会先于executable模块程式工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执行模块的dependency。

关于 ld-linux.so,可以参见我的另一篇文章

文件格式分析

readelf

这个工具和objdump命令提供的功能类似,但是它显示的信息更为具体,并且它不依赖BFD库(BFD库是一个GNU项目,它的目标就是希望通过一种统一的接口来处理不同的目标文件)

关于 ELF可以参考 这篇文章

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
$ readelf -all a.out
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x8048330
Start of program headers: 52 (bytes into file)
Start of section headers: 4412 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 9
Size of section headers: 40 (bytes)
Number of section headers: 30
Section header string table index: 27

Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048168 000168 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048188 000188 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 080481ac 0001ac 000020 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481cc 0001cc 000050 10 A 6 1 4
[ 6] .dynstr STRTAB 0804821c 00021c 00004c 00 A 0 0 1
[ 7] .gnu.version VERSYM 08048268 000268 00000a 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 08048274 000274 000020 00 A 6 1 4
[ 9] .rel.dyn REL 08048294 000294 000008 08 A 5 0 4
[10] .rel.plt REL 0804829c 00029c 000018 08 A 5 12 4
[11] .init PROGBITS 080482b4 0002b4 00002e 00 AX 0 0 4
[12] .plt PROGBITS 080482f0 0002f0 000040 04 AX 0 0 16
[13] .text PROGBITS 08048330 000330 00018c 00 AX 0 0 16
[14] .fini PROGBITS 080484bc 0004bc 00001a 00 AX 0 0 4
[15] .rodata PROGBITS 080484d8 0004d8 000011 00 A 0 0 4
[16] .eh_frame_hdr PROGBITS 080484ec 0004ec 000034 00 A 0 0 4
[17] .eh_frame PROGBITS 08048520 000520 0000c4 00 A 0 0 4
[18] .ctors PROGBITS 08049f14 000f14 000008 00 WA 0 0 4
[19] .dtors PROGBITS 08049f1c 000f1c 000008 00 WA 0 0 4
[20] .jcr PROGBITS 08049f24 000f24 000004 00 WA 0 0 4
[21] .dynamic DYNAMIC 08049f28 000f28 0000c8 08 WA 6 0 4
[22] .got PROGBITS 08049ff0 000ff0 000004 04 WA 0 0 4
[23] .got.plt PROGBITS 08049ff4 000ff4 000018 04 WA 0 0 4
[24] .data PROGBITS 0804a00c 00100c 000008 00 WA 0 0 4
[25] .bss NOBITS 0804a014 001014 000008 00 WA 0 0 4
[26] .comment PROGBITS 00000000 001014 00002a 01 MS 0 0 1
[27] .shstrtab STRTAB 00000000 00103e 0000fc 00 0 0 1
[28] .symtab SYMTAB 00000000 0015ec 000410 10 29 45 4
[29] .strtab STRTAB 00000000 0019fc 0001f9 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
INTERP 0x000154 0x08048154 0x08048154 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x005e4 0x005e4 R E 0x1000
LOAD 0x000f14 0x08049f14 0x08049f14 0x00100 0x00108 RW 0x1000
DYNAMIC 0x000f28 0x08049f28 0x08049f28 0x000c8 0x000c8 RW 0x4
NOTE 0x000168 0x08048168 0x08048168 0x00044 0x00044 R 0x4
GNU_EH_FRAME 0x0004ec 0x080484ec 0x080484ec 0x00034 0x00034 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
GNU_RELRO 0x000f14 0x08049f14 0x08049f14 0x000ec 0x000ec R 0x1

Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .ctors .dtors .jcr .dynamic .got

Dynamic section at offset 0xf28 contains 20 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x80482b4
0x0000000d (FINI) 0x80484bc
0x6ffffef5 (GNU_HASH) 0x80481ac
0x00000005 (STRTAB) 0x804821c
0x00000006 (SYMTAB) 0x80481cc
0x0000000a (STRSZ) 76 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x8049ff4
0x00000002 (PLTRELSZ) 24 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x804829c
0x00000011 (REL) 0x8048294
0x00000012 (RELSZ) 8 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x8048274
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x8048268
0x00000000 (NULL) 0x0

Relocation section '.rel.dyn' at offset 0x294 contains 1 entries:
Offset Info Type Sym.Value Sym. Name
08049ff0 00000206 R_386_GLOB_DAT 00000000 __gmon_start__

Relocation section '.rel.plt' at offset 0x29c contains 3 entries:
Offset Info Type Sym.Value Sym. Name
0804a000 00000107 R_386_JUMP_SLOT 00000000 printf
0804a004 00000207 R_386_JUMP_SLOT 00000000 __gmon_start__
0804a008 00000307 R_386_JUMP_SLOT 00000000 __libc_start_main

There are no unwind sections in this file.

Symbol table '.dynsym' contains 5 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.0 (2)
2: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2)
4: 080484dc 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used

Symbol table '.symtab' contains 65 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 08048154 0 SECTION LOCAL DEFAULT 1
2: 08048168 0 SECTION LOCAL DEFAULT 2
3: 08048188 0 SECTION LOCAL DEFAULT 3
4: 080481ac 0 SECTION LOCAL DEFAULT 4
5: 080481cc 0 SECTION LOCAL DEFAULT 5
6: 0804821c 0 SECTION LOCAL DEFAULT 6
7: 08048268 0 SECTION LOCAL DEFAULT 7
8: 08048274 0 SECTION LOCAL DEFAULT 8
9: 08048294 0 SECTION LOCAL DEFAULT 9
10: 0804829c 0 SECTION LOCAL DEFAULT 10
11: 080482b4 0 SECTION LOCAL DEFAULT 11
12: 080482f0 0 SECTION LOCAL DEFAULT 12
13: 08048330 0 SECTION LOCAL DEFAULT 13
14: 080484bc 0 SECTION LOCAL DEFAULT 14
15: 080484d8 0 SECTION LOCAL DEFAULT 15
16: 080484ec 0 SECTION LOCAL DEFAULT 16
17: 08048520 0 SECTION LOCAL DEFAULT 17
18: 08049f14 0 SECTION LOCAL DEFAULT 18
19: 08049f1c 0 SECTION LOCAL DEFAULT 19
20: 08049f24 0 SECTION LOCAL DEFAULT 20
21: 08049f28 0 SECTION LOCAL DEFAULT 21
22: 08049ff0 0 SECTION LOCAL DEFAULT 22
23: 08049ff4 0 SECTION LOCAL DEFAULT 23
24: 0804a00c 0 SECTION LOCAL DEFAULT 24
25: 0804a014 0 SECTION LOCAL DEFAULT 25
26: 00000000 0 SECTION LOCAL DEFAULT 26
27: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
28: 08049f14 0 OBJECT LOCAL DEFAULT 18 __CTOR_LIST__
29: 08049f1c 0 OBJECT LOCAL DEFAULT 19 __DTOR_LIST__
30: 08049f24 0 OBJECT LOCAL DEFAULT 20 __JCR_LIST__
31: 08048360 0 FUNC LOCAL DEFAULT 13 __do_global_dtors_aux
32: 0804a014 1 OBJECT LOCAL DEFAULT 25 completed.6086
33: 0804a018 4 OBJECT LOCAL DEFAULT 25 dtor_idx.6088
34: 080483c0 0 FUNC LOCAL DEFAULT 13 frame_dummy
35: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
36: 08049f18 0 OBJECT LOCAL DEFAULT 18 __CTOR_END__
37: 080485e0 0 OBJECT LOCAL DEFAULT 17 __FRAME_END__
38: 08049f24 0 OBJECT LOCAL DEFAULT 20 __JCR_END__
39: 08048490 0 FUNC LOCAL DEFAULT 13 __do_global_ctors_aux
40: 00000000 0 FILE LOCAL DEFAULT ABS a.c
41: 08049f14 0 NOTYPE LOCAL DEFAULT 18 __init_array_end
42: 08049f28 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
43: 08049f14 0 NOTYPE LOCAL DEFAULT 18 __init_array_start
44: 08049ff4 0 OBJECT LOCAL DEFAULT 23 _GLOBAL_OFFSET_TABLE_
45: 08048480 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
46: 08048482 0 FUNC GLOBAL HIDDEN 13 __i686.get_pc_thunk.bx
47: 0804a00c 0 NOTYPE WEAK DEFAULT 24 data_start
48: 00000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.0
49: 0804a014 0 NOTYPE GLOBAL DEFAULT ABS _edata
50: 080484bc 0 FUNC GLOBAL DEFAULT 14 _fini
51: 08049f20 0 OBJECT GLOBAL HIDDEN 19 __DTOR_END__
52: 0804a00c 0 NOTYPE GLOBAL DEFAULT 24 __data_start
53: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
54: 0804a010 0 OBJECT GLOBAL HIDDEN 24 __dso_handle
55: 080484dc 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
56: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
57: 08048410 97 FUNC GLOBAL DEFAULT 13 __libc_csu_init
58: 0804a01c 0 NOTYPE GLOBAL DEFAULT ABS _end
59: 08048330 0 FUNC GLOBAL DEFAULT 13 _start
60: 080484d8 4 OBJECT GLOBAL DEFAULT 15 _fp_hw
61: 0804a014 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
62: 080483e4 40 FUNC GLOBAL DEFAULT 13 main
63: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
64: 080482b4 0 FUNC GLOBAL DEFAULT 11 _init

Histogram for `.gnu.hash' bucket list length (total of 2 buckets):
Length Number % of total Coverage
0 1 ( 50.0%)
1 1 ( 50.0%) 100.0%

Version symbols section '.gnu.version' contains 5 entries:
Addr: 0000000008048268 Offset: 0x000268 Link: 5 (.dynsym)
000: 0 (*local*) 2 (GLIBC_2.0) 0 (*local*) 2 (GLIBC_2.0)
004: 1 (*global*)

Version needs section '.gnu.version_r' contains 1 entries:
Addr: 0x0000000008048274 Offset: 0x000274 Link: 6 (.dynstr)
000000: Version: 1 File: libc.so.6 Cnt: 1
0x0010: Name: GLIBC_2.0 Flags: none Version: 2

Notes at offset 0x00000168 with length 0x00000020:
Owner Data size Description
GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag)
OS: Linux, ABI: 2.6.15

Notes at offset 0x00000188 with length 0x00000024:
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 17fb9651029b6a8543bfafec9eea23bd16454e65

objdump

objdump工具用来显示二进制文件的信息,就是以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。

1
2
# 反汇编
$ objdump -d main.o

nm

nm指令是names的简称,通过该指令可以列举文件中的符号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$ cat > hello.c << "EOF"
#include <stdio.h>
int main() {
printf("hello world\n");
return 0;
}
EOF
$ gcc hello.c -o hello
$ name hello
0000000000601038 B __bss_start
0000000000601038 b completed.7594
0000000000601028 D __data_start
0000000000601028 W data_start
0000000000400460 t deregister_tm_clones
00000000004004e0 t __do_global_dtors_aux
0000000000600e18 t __do_global_dtors_aux_fini_array_entry
0000000000601030 D __dso_handle
0000000000600e28 d _DYNAMIC
0000000000601038 D _edata
0000000000601040 B _end
00000000004005b4 T _fini
0000000000400500 t frame_dummy
0000000000600e10 t __frame_dummy_init_array_entry
00000000004006f8 r __FRAME_END__
0000000000601000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
00000000004005d0 r __GNU_EH_FRAME_HDR
00000000004003c8 T _init
0000000000600e18 t __init_array_end
0000000000600e10 t __init_array_start
00000000004005c0 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000600e20 d __JCR_END__
0000000000600e20 d __JCR_LIST__
w _Jv_RegisterClasses
00000000004005b0 T __libc_csu_fini
0000000000400540 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000400526 T main
U puts@@GLIBC_2.2.5
00000000004004a0 t register_tm_clones
0000000000400430 T _start
0000000000601038 D __TMC_END__

参考资料