gcc⽣成反汇编linux_linux反汇编调试
反汇编有有以下⼏种⽅法:
1.使⽤gcc -S test.c 或者gcc -S test.c&
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的区别不是很⼤,在源码级调试的时候有⽤,要求
linux下gcc编译的四个步骤编译时使⽤了-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: 可反编译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”参数为空指针所致!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。