gcc生成反汇编 linux_linux反汇编调试
反汇编有有以下几种方法:1.使用gcc -S test.c 或者gcc -S test.c>out.txt2.使用gdb调试,在调试中输入disass 函数名 就可以3.objdump -D test 一般常用1,2两种,~~~~~C语言代码example.cint triangle( int width, int height){int arr{0,1,2,3,4};int area;ar
反汇编有有以下几种方法:
1.使用gcc -S test.c 或者gcc -S test.c>out.txt
2.使用gdb调试,在调试中输入disass 函数名 就可以
3.objdump -D test 一般常用1,2两种,
~~~~~C语言代码example.c
int triangle( int width, int height)
{
int arr{0,1,2,3,4};
int area;
area = width * height /2;
return (area);
}
void main()
{
triangle(5,4);
}
~~~~~gdb反汇编代码
$ gdb example
(gdb) disass main
Dump of assembler code for function main:
0x080483f6 : push %ebp
0x080483f7 : mov %esp,%ebp
0x080483f9 : sub $0x8,%esp
目标码格式列表
--demangle
-C 将底层的符号名解码成用户级名字,除了去掉所有开头的下划线之外,还使得C++函数名以可理解的方式显示出来。
—disassemble或者-d反汇编可执行段
.—dissassemble-all或者-D反汇编所有段
--debugging显示调试信息。企图解析保存在文件中的调试信息并以C语言的语法显示出来。仅仅支持某些类型的调试信息。
--prefix-addresses反汇编的时候,显示每一行的完整地址。这是一种比较老的反汇编格式。显示效果并不理想,但可能会用到其中的某些显示,自己可以对比。
--disassemble-zeroes 一般反汇编输出将省略大块的零,该选项使得这些零块也被反汇编。
-EB -EL 指定字节序 --endian={big|little}这个选项将影响反汇编出来的指令。little-endian就是我们当年在dos下玩汇编的时候常说的高位在高地址,x86都是这种。
--file-headers或者 -f 显示objfile中每个文件的整体头部摘要信息。
--section-headers;--headers 或者-h 显示目标文件各个section的头部摘要信息。
--info或者-i 显示对于 -b 或者 -m 选项可用的架构和目标格式列表。显示支持的目标文件格式和CPU架构
--section=name或者-j name 仅仅显示指定section的信息
--line-numbers或者-l 用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求编译时使用了-g之 类的调试编译选项。
--architecture=machine 或者-m machine指定反汇编目标文件时使用的架构,当待反汇编文件本身没有描述架构信息的时候(比如S-records),这个选项很有用。可以用-i选项列出这里能够指定的架构
--reloc或者-r 显示文件的重定位入口。如果和-d或者-D一起使用,重定位部分以反汇编后的格式显示出来。
--dynamic-reloc -R 显示文件的动态重定位入口,仅仅对于动态目标文件有意义,比如某些共享库。
--full-contents -s 显示指定section的完整内容。
objdump --section=.text -s inet.o | more
--source -S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,效果比较明显。隐含了-d参数。
--show-raw-insn反汇编的时候,显示每条汇编指令对应的机器码,除非指定了--prefix-addresses,这将是缺省选项。
--no-show-raw-insn
-S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,
效果比较明显。隐含了-d参数。
-l 用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用
使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求
编译时使用了-g之类的调试编译选项。
-j name 仅仅显示指定section的信息
如何使用linux下objdump命令对任意一个二进制文件进行反汇编?
可以使用如下命令:
objdump -D -b binary -m i386 a.bin
-D表示对全部文件进行反汇编,-b表示二进制,-m表示指令集架构,a.bin就是我们要反汇编的二进制文件
objdump -m可以查看更多支持的指令集架构,如i386:x86-64,i8086等
另外上面的所有objdump命令的参数同样适用于arm-linux-objdump。
同时我们也可以指定big-endian或little-endian(-EB或-EL),我们可以指定从某一个位置开始反汇编等。
objdump命令是Linux下的反汇编目标文件或者可执行文件的命令,它还有其他作用,下面以ELF格式可执行文件test为例详细介绍:
objdump -f test 显示test的文件头信息
objdump -d test 反汇编test中的需要执行指令的那些section
objdump -D test 与-d类似,但反汇编test中的所有section
objdump -h test 显示test的Section Header信息
objdump -x test 显示test的全部Header信息
objdump -s test 除了显示test的全部Header信息,还显示他们对应的十六进制文件代码
使用arm-linux 工具链里面的arm-linux-objdump 就能反汇编
cd到bin文件所在的目录, 在命令行下输入:
arm-linux-objdump -D -b binary -m arm xxx.bin > xxx.asm
参数:
-D 反编译所有代码
-m 主机类型, arm
-b 文件格式, binary
对于ELF格式的文件只要一个-D参数即可
就可以把xxx.bin反汇编到xxx.asm文件
Arm-linux-objdump –D elf_file > dis_file或者
Arm-linux-objdump –D –b binary –m arm bin_file > dis_file
内存地址反向查找出问题的程序:
<1>.通过汇编去查找.
windows 下c 语言调试 1. release 版编译/连接选项, 把"generate debug info/" 打钩选择
2.dumpbin /DISASM /OUT:dump.out.txt.1 prep.exe 可反编译exe文件
3.得到程序非法地址(可从管理工具-》事件查看器里得到),与汇编比较。
对目标文件:***.o:
arm-none-Linux-gnueabi-objdump -D ./kernel/sched.o > sched.S
对可执行文件***.bin:
arm-linux-objdump -D -b binary -m arm xxx.bin > xxx.asm
为了运行ARM汇编代码,需要使用交叉编译器arm-linux-gcc对ARM汇编代码进行编译。下载交叉编译器安装完毕后,对ARM汇编代码进行编译。
arm-linux-gcc main.s -o main -nostdlib
编译选项“-nostdlib”表示不使用任何运行时库文件,编译生成的可执行文件main只能在ARM体系结构的系统上运行。
通常认为,产生异常的地址是lr寄存器的值,从上面的异常信息可以看到[lr]的值是c01a4e30。
接下来,我们可以通过内核镜像文件反汇编来找到这个地址。内核编译完成后,会在内核代码根目录下生成vmlinux文件,我们可以通过以下命令来反汇编:
arm-none-eabi-objdump -Dz -Svmlinux >linux.dump
值得注意的是,arm-none-eabi-objdump的参数-S表示尽可能的把原来的代码和反汇编出来的代码一起呈现出来,-S参数需要结合 arm-linux-gcc编译参数-g,才能达到反汇编时同时输出原来的代码。所以,我在linux内核代码根目录的Makefile中增加-g编译参 数:
KBUILD_CFLAGS := -g -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
-fno-strict-aliasing -fno-common \
-Werror-implicit-function-declaration \
-Wno-format-security \
-fno-delete-null-pointer-checks
修改Makefile后,重新编译内核,在根目录中生成的vmlinux文件就会包含了原来的代码信息,因此,该文件的大小也比原来大一倍!
最后执行“arm-none-eabi-objdump -Dz-Svmlinux >linux.dump”,由于加入了-g编译参数,执行这个反汇编命令需要很长时间(本人在虚拟机上执行,花了近6个小时!),反汇编出来的linux.dump文件也比原来的44MB增大到惊人的503MB。
(博主加:这里有一点要注意,如果是ko模块文件,反汇编时如果想看到ko文件的某函数反汇编代码,该函数不能加static关键字修饰,而且module_init修饰的入口函数,其名字即为module_init)
接下来可以用UltraEdit打开linux.dump文件,查找“c01a4e30”字符串。
最后定位到的信息是:
==================================================================================================================
/*
* tasklet handling tty stuff outside the interrupt handler.
*/
static void atmel_tasklet_func(unsigned long data)
{
c01a4e20: e92d45f0 push {r4, r5, r6, r7, r8, sl, lr}
c01a4e24: e24dd01c sub sp, sp, #28 ; 0x1c
c01a4e28: e1a04000 mov r4, r0
/* The interrupt handler does not take the lock */
spin_lock(&port->lock);
if (atmel_use_pdc_tx(port))
atmel_tx_pdc(port);
else if (atmel_use_dma_tx(port))c01a4e2c: ebfffda1 bl c01a44b8
c01a4e30: e3500000 cmp r0, #0 ; 0x0c01a4e34: e5943034 ldr r3, [r4, #52]
c01a4e38: 0a00007b beq c01a502c
==================================================================================================================
可以看出来,异常的产生位于atmel_tasklet_func函数的else if (atmel_use_dma_tx(port))一行。
估计atmel_use_dma_tx(port)的“port”参数为空指针所致!
更多推荐
所有评论(0)