1.1 gdb
1) info registers : 显示所有寄存器的值
2 )print : 打印特定寄存器
(gdb) p $edi
print/d 显示 10进制
print/t 显示 2进制
print/x 显示 16进制
3) x 显示特定内存的位置 值
x/ABC
A : 个数
B : c 字符 d 同上
C : b 字节 ; h 字 ;w ;双字
(gdb) x/16cb &mystr
4) 从开始点
(gdb) b *_start
1.2 as
命令 as -o xxx.o xxx.s
as -o xxx.o -gstabs xxx.s 为了可以gdb
1.3 ld
命令 ld -o main main.o
如果需要系统调用 加上 运行时加载动态库的程序
ld -dynamic-linker /lib/ld-linux.so.2 -o main -lc main.o
使用原始系统调用好处
创建长度尽可能短的代码,执行最可能快的代码
因为他不需要把外部库链入 (不要加载动态加载程序)
C库 呢 移植 ,可共享,但是我清楚的记得 很多系统调用没有C库接口
或许你可以说他 can not be portable
当然以上所有的等同于 gcc -o main xxx.s
1.4 objdump -D main
1.5 strace
strace -c xxx
会列出一些 errors
strace -e trace = xxx,xxx
或者 直接 strace -p pid
二 架子
2.1 数据段
.data .rodata(read only)
2.1.1 标签:
.ascii 文本; .asciz 带空字符结尾的文本 ; .long .int ....
mystr:(相当于指针)
.ascii "Hello world"
2.1.2 静态符号(数据段)
output: .ascii "szx start\n" output_end: .equ len , output_end - output
.equ MYNAGE ,22
cmp $MYAGE, %eax
2.2 bss段
.comm 声明初始化的数据的通用内存区域
.lcomm 声明未初始化的数据的本地内存区域 (不能用在globl命令)
.seciont .bss
.lcomm buffer ,10
好处是不会让你编译后的文件包括你开的bss空间. 上图可能只是一个符号
一般查找PC指针出错的方法是 (如果gdb where 只能看到出错的register 和pc )
1 如果有ld 链接文件,那么直接分析文件 比如android 里面就有很多 .map的 链接映射文件 规定了代码段 库等分布
(这个以后会专门写一篇)
如果没有也可以 通过/proc/pidxxx/men 来查看具体的分布
2 这时候找到.so 或者数据段的基址 然后去根据 -g 编译出来的文件 反编译汇编 找到PC出错的行 ,一般就可以分析出原因了(以后会补个列子)
==================================
linux 系统中 分配给程序运行的虚拟地址从
0x80480000 开始
使用 objdump -x 可执行 .可以获得内存布局 (readelf -e 或许更好 ^^)
08048148 l d .note.ABI-tag 00000000 .note.ABI-tag
08048168 l d .note.gnu.build-id 00000000 .note.gnu.build-id
0804818c l d .gnu.hash 00000000 .gnu.hash
080481ac l d .dynsym 00000000 .dynsym
0804820c l d .dynstr 00000000 .dynstr
0804825e l d .gnu.version 00000000 .gnu.version
0804826c l d .gnu.version_r 00000000 .gnu.version_r
0804828c l d .rel.dyn 00000000 .rel.dyn
08048294 l d .rel.plt 00000000 .rel.plt
080482b4 l d .init 00000000 .init
080482e4 l d .plt 00000000 .plt
08048340 l d .text 00000000 .text
080484ec l d .sched.text 00000000 .sched.text
08048500 l d .fini 00000000 .fini
0804851c l d .rodata 00000000 .rodata
08048548 l d .eh_frame 00000000 .eh_frame
08049f0c l d .ctors 00000000 .ctors
08049f18 l d .dtors 00000000 .dtors
08049f24 l d .jcr 00000000 .jcr
08049f28 l d .dynamic 00000000 .dynamic
08049ff0 l d .got 00000000 .got
08049ff4 l d .got.plt 00000000 .got.plt
0804a010 l d .data 00000000 .data
0804a018 l d .bss 00000000 .bss
其实.init .sched.text 在kernel 中可以看到进常通过gcc 特性用
#define __sched __attribute__((__section__(".sched.text")))
来指定
如果你 gdb where
发现都是一排 十六进制地址 没有任何源码信息 不要慌着
记得加上-g 编译后 用 objdump -D 翻译成 汇编 ,
然后去找这些地址 , 当然你需要知道一些C 风格的汇编 格式(入stack 局部变量保存 等)
==========================
有时候如果你没有nm 或者ldd 来看系统当前连接的动态库, 何不直接vi 可执行文件,然后 /???.so 这样看
屡试不爽哦
当然也可以直接 readelf .....
http://www.cnblogs.com/napoleon_liu/archive/2011/05/06/2038698.html