本文由zengl.com站长对
http://pan.baidu.com/share/link?shareid=3717576860&uk=940392313 汇编教程英文版相应章节进行翻译得来。
另外再附加一个英特尔英文手册的共享链接地址:
http://pan.baidu.com/share/link?shareid=2345340326&uk=940392313 (在某些例子中会用到)
本篇翻译对应汇编教程英文原著的81到90页。
The GNU Linker (GNU链接器):
GNU链接器,对应的是ld程序,它是用于将目标代码文件链接为可执行程序或者库文件的工具。ld程序也是GNU binutils软件包的一部分,所以如果你已经安装了GNU汇编器的话,这个链接器应该也装好了。
下面是ld程序的命令行参数格式:
ld [-o output] objfile...
[-Aarchitecture] [-b input-format] [-Bstatic]
[-Bdynamic] [-Bsymbolic] [-c commandfile] [--cref]
[-d|-dc|-dp]
[-defsym symbol=expression] [--demangle]
[--no-demangle] [-e entry] [-embedded-relocs] [-E]
[-export-dynamic] [-f name] [--auxiliary name]
[-F name] [--filter name] [-format input-format]
[-g] [-G size] [-h name] [-soname name] [--help]
[-i] [-lar] [-Lsearchdir] [-M] [-Map mapfile]
[-m emulation] [-n|-N] [-noinhibit-exec]
[-no-keep-memory] [-no-warn-mismatch] [-Olevel]
[-oformat output-format] [-R filename] [-relax]
[-r|-Ur] [-rpath directory] [-rpath-link directory]
[-S] [-s] [-shared] [-sort-common]
[-split-by-reloc count] [-split-by-file]
[-T commandfile]
[--section-start sectionname=sectionorg]
[-Ttext textorg] [-Tdata dataorg] [-Tbss bssorg]
[-t] [-u sym] [-V] [-v] [--verbose] [--version]
[-warn-common] [-warn-constructors]
[-warn-multiple-gp] [-warn-once]
[-warn-section-align] [--whole-archive]
[--no-whole-archive] [--wrap symbol] [-X] [-x] |
尽管看起来有很多的命令行参数,但是在实际用的时候,同一时刻并不需要用到很多参数。这表明GNU链接器是一个非常灵活的程序,有很多不同的功能。下表描述了这些命令参数的含义:
Parameter |
Description |
-b |
Specifies the format of the object code input files.
指定目标代码输入文件对应的格式 |
-Bstatic |
Use only static libraries.
仅使用静态库,主要影响后面的-l库搜索选项 |
-Bdynamic |
Use only dynamic libraries.
仅使用动态库,主要影响后面的-l库搜索选项 |
-Bsymbolic |
Bind references to global symbols in shared libraries.
在共享库中将引用绑定到全局符号 |
-c |
Read commands from the specified command file.
从指定的命令文件中读取命令,
命令文件是一种MRI的脚本文件 |
--cref |
Create a cross-reference table.
创建一个交叉引用表 |
-d |
Assign space to common symbols even if relocatable
output is specified.
为常用符号分配空间,即使指定了重定位输出 |
--defsym |
Create the specified global symbol in the output file.
在输出文件中创建指定的全局符号 |
-e |
Use the specified symbol as the beginning
execution point of the program.
使用指定的符号作为程序的执行入口 |
-E |
For ELF format files, add all symbols to
the dynamic symbol table.
对于ELF格式的文件,将程序里所有的符号添加
到动态符号表中,这样在动态加载某些动态链接库时,
这些库就可以引用到这些程序里的符号信息 |
-f |
For ELF format shared objects,
set the DT_AUXILIARY name.
设置ELF格式的共享对象内部的DT_AUXILIARY字段名称 |
-F |
For ELF format shared objects,
set the DT_FILTER name.
设置共享对象内部的DT_FILTER字段名称 |
--format |
Specify the format of the object code input files
(same as -b).
和-b选项一样,用于指定目标代码输入文件的格式 |
-g |
Ignored. Used for compatibility with other tools.
被忽略的选项,用于兼容其他的工具 |
-h |
For ELF format shared objects,
set the DT_SONAME name.
设置共享对象内部的DT_SONAME字段名称 |
-i |
Perform an incremental link.
执行一个增量链接 |
-l |
Add the specified archive file to the
list of files to link.
为链接器添加需要链接的库文件 |
-L |
Add the specified path to the list of directories
to search for libraries.
添加指定的库文件搜索目录 |
-M |
Display a link map for diagnostic purposes.
在标准输出中打印出用于调试的链接映射信息 |
-Map |
Create the specified file to contain the link map.
将链接映射信息输出到指定的文件中 |
-m |
Emulate the specified linker.
模拟指定的链接器 |
-N |
Set the text and data sections to be
readable and writable.
将代码段和数据段设置为可读和可写 |
-n |
Sets the text section to be read only.
将代码段设置为只读 |
--noinhibit-exec |
Produce an output file even if
non-fatal link errors appear.
即使在链接过程中出现了非严重型错误,
也生成输出文件 |
--no-keep-memory |
Optimize link for memory usage.
在内存使用方面对链接进行优化,
这在链接大型的可执行程序会占用很多内存时
可能需要用到 |
--no-warn-mismatch |
Allow linking mismatched object files.
允许链接非匹配的输入对象文件,
有时候某些输入文件可能因某些原因使用
不同处理器指令格式等编译的,就会导致不匹配,
然后输出警告信息,该选项可以不产生此警告,
默许不匹配行为 |
-O |
Generate optimized output files.
生成优化过的输出文件 |
-o |
Specify the name of the output file.
指定输出文件的文件名 |
-oformat |
Specify the binary format of the output file.
指定输出文件的二进制格式 |
-R |
Read symbol names and addresses
from the specified filename.
从指定文件中读取符号名和对应的地址 |
-r |
Generates relocatable output
(called partial linking).
生成重定位表输出,这个过程被称作部分链接 |
-rpath |
Add the specified directory to the runtime library search path.
添加指定目录到运行时库的搜索路径中 |
-rpath-link |
Specify a directory to search for runtime shared libraries.
指定一个目录用于搜索运行时共享库 |
-S |
Omits debugger symbol information from the output file.
去掉输出文件中用于调试的符号信息 |
-s |
Omits all symbol information from
the output file.
去掉输出文件中所有的符号信息 |
-shared |
Create a shared library.
创建一个共享库 |
--sort-common |
This option tells ld to sort the common symbols by size when it places them in the appropriate output sections.
当在输出段放置常规符号时,按大小顺序来排列 |
--split-by-reloc |
Creates extra sections in the output file
based on the specified size.
在输出文件中按指定大小创建额外的段 |
--split-by-file |
Creates extra sections in the output file for each object file.
在输出文件中为每个对象文件创建额外的段 |
--section-start |
Locates the specified section in the output file at the specified address.
将输出文件中指定的段定位到指定的地址 |
-T |
Specifies a command file (same as -c).
和-c选项一样,指定一个链接脚本文件 |
-Ttext |
Use the specified address as the starting point for the text section.
设置代码段的起始地址 |
-Tdata |
Use the specified address as the starting point for the data section.
设置数据段的起始地址 |
-Tbss |
Use the specified address as the starting point for the bss section.
设置bss段的起始地址 |
-t |
Displays the names of the input files as they are being processed.
当输入文件被处理的时候,显示出它们的名称 |
-u |
Forces the specified symbol to be in the output file as an undefined symbol.
为输出文件指定未定义符号 |
--warn-common |
Warn when a common symbol
is combined with another common symbol.
当一个常规符号和另一个常规符号结合时产生警告信息 |
--warn-constructors |
Warn if any global constructors are used.
当全局构造函数被使用时产生警告信息 |
--warn-once |
Warn only once for each undefined symbol.
对于每个未定义的符号只产生一次警告 |
--warn-section-align |
Warn if the output section address is changed due to alignment.
当输出段地址因为对齐而被改变时产生
对应的警告信息 |
--whole-archive |
For the specified archive files, include all of the files in the archive.
包含指定库中的所有文件 |
-X |
Delete all local temporary symbols.
删除所有的临时的局部符号 |
-x |
Delete all local symbols.
删除所有的局部符号 |
|
下面的命令是链接器将汇编器生成的目标代码文件转为可执行文件的最简单的例子:
$ ld –o test test.o
$ ls -al test
-rwxr-xr-x 1 rich rich 787 Jul 6 11:53 test
$ ./test
Hello world!
$ |
上面例子中ld链接器通过-o选项将之前汇编器生成的test.o链接成test可执行文件,并且给予了test可执行文件适当的unix权限,从上面的输出可以看出来,链接器自动为生成的test程序设置了unix下的755的访问模式(即rwxr-xr-x的访问控制),该访问控制模式允许系统中的任何用户执行该程序,但是只有创建人可以修改test程序。
The GNU Compiler (GNU编译器):
GNU编译器即gcc不仅在开源的linux及BSD系统上很流行,而且在很多商业的unix发行版中也被广泛使用。
gcc具有编译多种不同的高级编程语言的能力,在英文原著写作的时候,gcc已经可以编译如下几种高级语言:
-
C
-
C++
-
Objective-C 扩充C的面向对象编程语言
-
Fortran
-
Java
-
Ada
gcc除了提供C及C++的编译工具外,还提供了运行C及C++所需要的库文件。下面就介绍如何在你的系统中安装gcc,以及如何使用它来编译高级编程语言。
Downloading and installing gcc (下载安装gcc):
许多unix系统默认就装好了gcc等开发环境,对于使用RPM包管理器的系统,你可以使用下面的命令来检测gcc是否已经安装:
$ rpm -qa | grep gcc
gcc-cpp-2.96-0.48mdk
gcc-2.96-0.48mdk
gcc-c++-2.96-0.48mdk
$ |
上面的输出表明当前系统中已经安装了2.96版本的gcc 。如果你的系统中没有安装gcc ,那么首先检查Linux发行光盘中是否有安装包,有就直接安装即可,需要注意的是,gcc软件包和binutils软件包一样,包含了许多库文件,必须确保这些库文件与当前系统中运行的程序是相兼容的,否则就会出现很严重的问题。
如果当前unix系统中还没安装过gcc软件包,那么你可以从gcc的官网下载到gcc的二进制执行文件(因为你目前还没有编译器,无法编译源代码),gcc的官网是
http://gcc.gnu.org/
英文原著编写的时候,gcc最新版本为3.4 ,译者翻译的时候,最新版本为4.8.1 。如果最新版的gcc软件包里没有可以直接运行的二进制执行文件,那么可以先下载一个可用的旧版本的gcc,然后用旧版本的gcc来编译新版本的源代码即可。
Using gcc (gcc的使用):
根据要编译的源代码和操作系统的底层硬件平台,gcc可以有多种不同的命令行格式。其中gcc通用的命令行格式如下:
gcc [-c|-S|-E] [-std=standard]
[-g] [-pg] [-Olevel]
[-Wwarn...] [-pedantic]
[-Idir...] [-Ldir...]
[-Dmacro[=defn]...] [-Umacro]
[-foption...] [-mmachine-option...]
[-o outfile] infile... |
gcc命令行参数的含义如下表所示:
Parameter |
Description |
-c |
Compile or assemble code, but do not link
只进行编译或汇编,不进行链接 |
-S |
Stop after compiling, but do not assemble
编译阶段完成后就停止,不进行汇编 |
-E |
Stop after preprocessing, but do not compile
预处理阶段结束后就停止,不进行编译 |
-o |
Specifies the output filename to use
指定输出文件的文件名 |
-v |
Display the commands used at each stage of compilation
显示编译过程中每个阶段所使用过的命令 |
-std |
Specifies the language standard to use
指定要使用的语言标准 |
-g |
Produce debugging information
生成调试信息 |
-pg |
Produce extra code used by gprof for profiling
生成额外的信息,这些信息可以在gprof中用于统计分析程序的执行性能 |
-O |
Optimize executable code
优化可执行代码 |
-W |
Sets compiler warning message level
设置编译器要输出的警告消息的级别 |
-pedantic |
Issue mandatory diagnostics listing in the C standard
关闭所有的GNU扩展 |
-I |
Specify directories for include files
指定include包含文件的目录 |
-L |
Specify directories for library files
指定库文件所在的目录 |
-D |
Predefine macros used in the source code
预定义源代码中可以使用的宏 |
-U |
Cancel any defined macros
取消任何定义过的宏 |
-f |
Specify options used to control the behavior of the compiler
指定一些可以控制编译器行为的选项 |
-m |
Specify hardware-dependant options
指定一些和硬件依赖相关的选项 |
|
和链接器一样,尽管gcc也有很多的参数,但大多数情况下,你只需使用其中一部分参数即可。如果你想对程序使用调试器,可以使用-g参数。对于linux系统,通过-gstabs参数可以在程序中为GNU调试器添加一些额外的调试信息。
下面创建一个简单的C程序来测试编译器:
#include <stdio.h>
int main()
{
printf(“Hello, world!\n”);
exit(0);
} |
将该程序文件命名为ctest.c ,然后就可以使用如下的命令来进行编译和测试:
$ gcc -o ctest ctest.c
$ ls -al ctest
-rwxr-xr-x 1 rich rich 13769 Jul 6 12:02 ctest*
$ ./ctest
Hello, world!
$ |
上面命令中,gcc通过-o参数直接创建了ctest的可执行文件,并赋予了它可执行权限,这个命令并不会产生中间的目标代码,要产生中间文件需要使用其他的参数。运行ctest,程序在终端打印出了hello world的字符串信息,这和源代码是一致的。
如果要查看gcc编译下,源代码对应的汇编程序,可以使用-S参数,如下所示:
$ gcc -S ctest.c
$ cat ctest.s
.file “ctest.c”
.version “01.01”
gcc2_compiled.:
.section .rodata
.LC0:
.string “Hello, world!\n”
.text
.align 16
.globl main
.type main,@function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
subl $12, %esp
pushl $.LC0
call printf
addl $16, %esp
subl $12, %esp
pushl $0
call exit
.Lfe1:
.size main,.Lfe1-main
.ident “GCC: (GNU) 2.96 20000731 (Linux-Mandrake 8.0 2.96-0.48mdk)”
$ |
ctest.s文件显示了编译器是如何创建汇编语言指令来实现C语言源代码的。查看这些汇编代码将有助于优化C源代码,在汇编代码中调用了两个C函数:printf和exit ,在后面的章节中将介绍汇编语言如何使用C的库函数。
The GNU Debugger Program (GNU调试器):
许多专业的程序员使用GNU调试器即gdb来调试C及C++程序,但是gdb还可以调试汇编程序,下面就对gdb的安装使用进行说明,英文原著中的汇编例子也是使用gdb来作为调试器的。
Downloading and installing gdb (下载安装gdb):
gdb和gcc一样,默认在很多linux和BSD系统中已经装好了,你可以使用如下命令来进行检测:
$ rpm -qa | grep gdb
libgdbm1-1.8.0-14mdk
libgdbm1-devel-1.8.0-14mdk
gdb-5.0-11mdk
$ |
上面的输出表明当前系统中已经装好了5.0版本的gdb ,同时还安装了两个gdb会用到的库软件包。
如果你的系统中还没有安装gdb ,可以进入官网:
https://www.gnu.org/software/gdb/ 或者使用FTP:
ftp://sources.redhat.com/pub/gdb/releases/ ,在该ftp中下载需要的版本,例如gdb-7.6.tar.gz ,然后使用下面的命令:
该命令会创建一个gdb-7.6的目录,里面有gdb的源代码文件,然后进入该目录,使用下面命令进行编译:
编译成功后,使用make install将gdb的相关程序安装到常规位置,以供他人使用。
Using gdb (使用gdb):
gdb的命令行格式如下所示:
gdb [-nx] [-q] [-batch] [-cd=dir] [-f] [-b bps] [-tty=dev]
[-s symfile] [-e prog] [-se prog] [-c core] [-x cmds] [-d dir]
[prog[core|procID]] |
这些命令行参数的作用如下表所示:
Parameter |
Description |
-b |
Set the line speed of the serial interface for
remote debugging
设置远程调试串行接口的数据流的速度 |
-batch |
Run in batch (not interactive) mode.
Execute commands from file. Requires -x option.
运行在批处理模式(而非交互模式),从-x选项指定的文件
中读取GDB命令来执行 |
-c |
Specify the core dump file to analyze
指定核心的dump文件,用于分析 |
-cd |
Specify the working directory
指定工作目录 |
-d |
Specify a directory to search for source files
指定用于搜索源文件的目录 |
-e |
Specify the file to execute
指定要执行的文件 |
-f |
Output filename and line numbers in
standard format when debugging
当调试时以标准格式输出文件名和行号 |
-nx |
Do not execute commands from ~/.gdbinit
initialization file
不执行~/.gdbinit初始化文件里的命令 |
-q |
Do not print the introductory and
copyright messages.
不打印引言和版权信息 |
-s |
Specify the filename for symbols
从-s参数指定的文件中读取符号表信息 |
-se |
Specify the filename for both symbols
and to execute
同时指定符号表文件和要执行的文件 |
-tty |
Set device for standard input and output
设置标准输入和输出设备 |
-x |
Execute gdb commands from the specified file
从指定的文件中读取执行gdb命令 |
|
要使用gdb ,那么要调试的可执行文件必须使用-gstabs参数进行编译,这样在可执行文件中才会包含所需的调试信息,gdb运行时,会给用户提供一个命令行接口,可以在其中输入调试命令:
$ gcc -gstabs -o ctest ctest.c
$ gdb ctest
GNU gdb 5.0mdk-11mdk Linux-Mandrake 8.0
Copyright 2001 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details.
This GDB was configured as “i386-mandrake-linux”...
(gdb) |
在gdb命令提示符下,你可以输入相关调试命令,比较常用的调试命令如下表所示:
Command |
Description |
break |
Set a breakpoint in the source code
to stop execution
在源代码中设置断点,当程序执行到断点时
暂停执行 |
watch |
Set a watchpoint to stop execution
when a variable reaches a specific value
设置检测点,当检测条件达到时,暂停执行 |
info |
Observe system elements, such as registers,
the stack, and memory
显示出一些系统信息,例如寄存器信息,
栈信息,内存信息等 |
x |
Examine memory location
查看某内存位置的值 |
print |
Display variable values
查看某变量的值 |
run |
Start execution of the program
within the debugger
在调试器内开始执行需要调试的程序 |
list |
List specified functions or lines
列举显示出指定的函数或某行附近的源代码 |
next |
Step to the next instruction in the program
单步执行下一条指令,不会进入函数调用内部 |
step |
Step to the next instruction in the program
单步执行下一条指令,遇到函数调用,
可以进入函数执行 |
cont |
Continue executing the program
from the stopped point
从断点继续执行程序 |
until |
Run the program until it reaches the
specified source code line (or greater)
运行程序直到遇到指定的源代码行 |
|
下面是gdb调试的简单例子:
(gdb) list
1 #include <stdio.h>
2
3 int main()
4 {
5 printf(“Hello, world!\n”);
6 exit(0);
7 }
(gdb) break main
Breakpoint 1 at 0x8048496: file ctest.c, line 5.
(gdb) run
Starting program: /home/rich/palp/ctest
Breakpoint 1, main () at ctest.c:5
5 printf(“Hello, world!\n”);
(gdb) next
Hello, world!
6 exit(0);
(gdb) next
Program exited normally.
(gdb) quit
$ |
上面先通过list来查看程序的C源代码,然后使用break main在main入口函数下一个断点,接着run运行程序,程序在main函数入口处暂停执行,并等待用户进一步输入调试命令,通过next命令来单步执行,执行过程中可以查看到程序打印出来的信息,程序结束后,你既可以再运行一次程序,还可以使用quit命令来彻底退出gdb调试器。
限于篇幅,先写到这里,欲知后事如何,且听下回分解。。。
OK,到这里,休息,休息一下 o(∩_∩)o~~