GNU binutils文档格式.docx
《GNU binutils文档格式.docx》由会员分享,可在线阅读,更多相关《GNU binutils文档格式.docx(8页珍藏版)》请在冰豆网上搜索。
v:
显示ar操作的附加信息
创建动态库(利用gcc,未用ar)
(1)生成目标文件
$gcc-Wall-c-fpicfile1.cfile2.cfile3.c
-fpic:
指定生成的.o目标文件可被重定址.pic是positionidependentcode的缩写:
位置无关代码.
(2)生成动态库文件
$gcc-shared-olibNAME.sofile1.ofile2.ofile3.o
一般地,连接器使用main()函数作为程序入口.但在动态共享库中没有这样的入口.所以就要指定-shared选项来避免编译器显示出错信息.
实际上,上述的两条命令可以合并为下面这条:
$gcc-Wall-shared-fpic-olibNAME.sofile1.cfile2.cfile3.c
此后,将main函数所在的程序与libNAME.so连接
至此,与动态库连接的函数编译成了一个可执行文件。
貌似成功了,但还差最后一步。
如果直接运行该程序,会给出这样的错误信息:
errorwhileloadingsharedlibraries:
libhello.so:
cannotopensharedobjectfile:
Nosuchfileordirectory
这是因为与动态库连接的程序在运行时,首先将该动态库加载到内存中,而gcc默认加载动态库文件所在目录为/usr/local/lib,/usr/lib。
刚才的程序虽然能编译成功,但如果我们自己建立的动态库没有位于默认目录中,则执行时会应为无法找到它而失败。
解决办法:
改变加载路径对应的环境变量,然后再执行。
exportLD_LIBRARY_PATH=动态库所在目录:
$LD_LIBRARY_PATH
查看archive内容
$artvarchiveNAME
t:
显示archive中member的内容,若不指定member,则列出所有。
v:
与t结合使用时,显示member的详细信息。
要想进了解ar的详细选项,参考ar的on-linemanual
nm
nm用来列出目标文件中的符号,可以帮助程序员定位和分析执行程序和目标文件中的符号信息和它的属性。
如果没有目标文件作为参数传递给nm,nm假定目标文件为a.out.
这里用一个简单的示例程序来介绍nm的用法:
main.c:
intmain(intargc,char*argv[])
{
hello();
bye();
return0;
}
hello.c:
voidhello(void)
printf("
hello!
\n"
);
bye.c:
voidbye(void)
goodbye!
运行下列命令:
$gcc-Wall-cmain.chello.cbye.c
gcc生成main.o,hello.o,bye.o三个目标文件(这里没有声明函数原型,加了-Wall,gcc会给出警告)
$nmmain.ohello.obye.o
结果显示如下:
main.o:
Ubye
Uhello
00000000Tmain
hello.o:
00000000Thello
Uputs
bye.o:
00000000Tbye
结合这些输出结果,以及程序代码,可以知道:
对于main.o,bye和hello未被定义,main被定义了
对于hello.o,hello被定义了,puts未被定义
对于bye.o,bye被定义了,puts未被定义
几个值得注意的问题:
(1)"
目标文件"
指.o文件,库文件,最终的可执行文件
.o:
编译后的目标文件,即含有最终编译出的机器码,但它里面所引用的其他文件中函数的内存位置尚未定义.
(2)如果用nm查看可执行文件,输出会比较多,仔细研究输出,可以对nm用法有更清醒的认识.
(3)在上述hello.c,bye.c中,调用的是printf(),而nm输出中显示调用的是puts(),说明最终程序实际调用的puts(),如果令hello.c或bye.c中的printf()使用格式化输出,则nm显示调用printf().(如:
printf("
%d"
1);
)
关于nm的参数选项,参考on-linemanual
objcopy
objcopy可以将一种格式的目标文件转化为另外一种格式的目标文件.它使用GNUBFD库进行读/写目标文件.使用BFD,objcopy就能将原格式的目标文件转化为不同格式的目标文件.
以我们在nm中使用的hello.o目标文件和hello可执行为例:
$filehello.ohello
file命令用来判别文件类型,输出如下:
ELF32-bitLSBrelocatable,Intel80386,version1(SYSV),notstripped
hello:
ELF32-bitLSBexecutable,Intel80386,version1(SYSV),forGNU/Linux2.2.0,dynamicallylinked(usessharedlibs),notstripped
现在运行objcopy来改变hello的文件类型:
原先它是ELF格式的可执行程序,现将它转换为srec格式.srec格式文件是MotoloraS-Record格式的文件,主要用来在主机和目标机之间传输数据.
$objcopy-Osrechellohello_srec
file命令结果:
hello_srec:
MotorolaS-Record;
binarydataintextformat
注意objcopy的格式,"
-O"
指定输出文件类型;
输入文件名和输出文件名位于命令末尾.关于objcopy命令的详细选项,参考on-linemanual
objdump
objdump用来显示目标文件的信息.可以通过选项控制显示那些特定信息.objdump一个最大的用处恐怕就是将C代码反汇编了.在嵌入式软件开发过程中,也可以用它查看执行文件或库文件的信息.
下面我们用上文提到的hello可执行文件和hello_srec可执行文件为例,介绍objdump的简单用法:
$objdump-fhellohello_srec
输出如下:
fileformatelf32-i386
architecture:
i386,flags0x00000112:
EXEC_P,HAS_SYMS,D_PAGED
startaddress0x080482c0
hello_srec:
fileformatsrec
UNKNOWN!
flags0x00000000:
startaddress0x00000000080482c0
-f:
显示目标文件的头文件概要信息.
生成反汇编代码:
$objdump-dhello.o
显示如下:
Disassemblyofsection.text:
00000000<
hello>
:
0:
55
push
%ebp
1:
89e5
mov
%esp,%ebp
3:
83ec08
sub
$0x8,%esp
6:
83ec0c
$0xc,%esp
9:
6800000000
$0x0
e:
e8fcffffff
call
f<
hello+0xf>
13:
83c410
add
$0x10,%esp
16:
c9
leave
17:
c3
ret
-d:
显示目标文件中机器指令使用的汇编语言.只反汇编那些应该含有指令机器码的节(显示.text段);
如果用-D,则反汇编所有节的内容.
关于objcopy命令的详细选项,参考on-linemanual
readelf
readelf用来显示ELF格式目标文件的信息.可通过参数选项来控制显示哪些特定信息.(注意:
readelf不支持显示archive文档,也不支持64位的ELF文件).
下面利用先前的hello可执行文件演示readelf的简单用法:
$readelf-hhello
ELFHeader:
Magic:
7f454c46010101000000000000000000
Class:
ELF32
Data:
2'
scomplement,littleendian
Version:
1(current)
OS/ABI:
UNIX-SystemV
ABIVersion:
0
Type:
EXEC(Executablefile)
Machine:
Intel80386
0x1
Entrypointaddress:
0x80482c0
Startofprogramheaders:
52(bytesintofile)
Startofsectionheaders:
3848(bytesintofile)
Flags:
0x0
Sizeofthisheader:
52(bytes)
Sizeofprogramheaders:
32(bytes)
Numberofprogramheaders:
7
Sizeofsectionheaders:
40(bytes)
Numberofsectionheaders:
34
Sectionheaderstringtableindex:
31
注意:
readelf只能用于ELF格式目标文件,且选项中至少要指定一个(除V,H外)的选项!
gprof
gprof被用来测量程序的性能.它记录每个函数被调用的次数以及相应的执行时间.这样就能锁定程序执行时花费时间最多的部分,对程序的优化就可集中于对它们的优化.
用一个简单的数值计算程序来掩饰gprof的用法:
collatz.c:
#include<
stdio.h>
/*ComputesthelengthofCollatzsequences*/
unsignedintstep(unsignedintx)
if(x%2==0)
{
return(x/2);
}
else
return(3*x+1);
unsignedintnseq(unsignedintx0)
unsignedinti=1,x;
if(x0==1||x0==0)
returni;
x=step(x0);
while(x!
=1&
&
x!
=0)
x=step(x);
i++;
intmain(void)
unsignedinti,m=0,im=0;
for(i=1;
i<
500000;
i++)
unsignedintk=nseq(i);
if(k>
m)
m=k;
im=i;
printf("
sequencelength=%ufor%u\n"
m,im);
return0;
先将collatz.c编译成目标文件collatz.o,gcc通过-pg选项来打开gprof支持:
$gcc-Wall-c-pgcollatz.c
$gcc-Wall-pg-ocollatzcollatz.o
注意:
两条命令都要加"
-pg"
选项。
前一条命令生成collatz.o目标文件。
后一条命令生成可执行文件,该可执行文件中包含了记录函数执行时间的指令。
生成collatz可执行文件后,现执行它,结果与一般程序的执行无疑。
但此时在PWD目录生成一个名为"
gmon.out"
的文件,gprof通过它来分析程序的执行。
如果不现执行程序,而直接用gprof来分析它,会提示“gmon.out:
Nosuchfileordirectory”。
gprof用法:
$gprof./collatz
转自:
Tags:
bintuils