**4.4**在汇编语言中使用C语言库函数

来源:互联网 发布:新时代电话软件 编辑:程序博客网 时间:2024/05/20 10:10

##承接上一篇

**4.4**在汇编语言中使用C语言库函数

上一个程序使用Linux系统调用显示CPU厂商信息。还有一种不使用系统调用的方法,那就是使用C语言库函数。

接下来通过调用C库函数的printf()函数,编写一个调用printf()函数的新cpuid.s。

*4.4.1*使用printf

C库包含很多C程序通用的很多函数。比如exit()和printf()。新的cpuid.s中的Linux系统调用将被C库函数所替代。

clib_cpuid.s如下:

.section .dataoutput:     .asciz “The cpu id  ‘%s’\n”.section .bss    . lcomm  buffer, 12.section .text.globl _start_start:movl $0 ,%eaxcpuidmovl $buffer, %edimovl  %ebx,  (%edi)movl  %edx,  4(%edi)movl  %ecx,   8(%edi)pushl $outputpushl  $buffercall printfaddl $8, %esppushl $0call exit

编译 & 连接:

$ as -o clib_cpuid.o clib_cpuid.s

$ ld -dynamic-linker /lib/l-linux.so.2 -o clib_cpuid -lc clib_cpuid.o

如果你是32bit系统,不出意外可以成功的运行的。

接下来解释下。

printf()函数需要两个参数,第一个是输出的字符串,这里字符串是带有显示变量的字符串。

而且printf函数要求以空字符结尾的字符串。.asciz命令定义的字符串末尾是空字符。

接下来在.bss段创建了一个缓冲区,这个缓冲区将要包含cpuid的信息。使用.lcomm命令将其声明为12字节的缓冲区。在将CPUID信息传递到缓冲区的过程和原来的程序的过程是一样的。

为了使用C库函数printf,需要使用pushl将需要的参数入栈。

需要注意的是入栈顺序和printf函数的参数表顺序是相反的。即就是首先将缓冲区buffer入栈,随后是output入栈。入栈完成之后,使用call指令调用printf函数。addl指令用于清空printf函数放入堆栈的指令。使用exit函数的技术和printf函数相同。

*4.4.2*连接C库函数

简单地说,在汇编语言程序中调用C库函数,必须把C库文件连接到程序目标代码。如果C库函数不可用,显然要报错。

Linux系统上,把C函数连接到汇编语言方法有两种。第一种称为静态连接:将函数目标代码直接连接到程序可执行文件中。这样造成创建了巨大的可执行程序,如果同时运行程序的多个实例(也就是进程),将会造成内存的浪费。第二种称为动态链接:动态链接使用库的方式允许程序员可以在应用程序中引用函数。但是不把函数代码连接到可执行程序文件,程序运行时由操作系统调用动态链接库。还有个好处是多个程序可以共享动态链接库。

Linux系统中,标准的C动态链接库位于lib.so.x,x代表版本。这个库文件包含了标准C函数:包括printf和exit。

当我们使用gcc时,自动帮我们连接到了动态链接库。但是在这里我们需要手动地将动态链接库连接到程序目标代码以便C函数可以操作。

GNU连接器使用 -l 参数,在使用这个参数时不需要指定库名称,默认的库是 :/lib/libx.so。但是还必须指定在运行时加载动态库的程序。Linux中这个程序是ld-linux.so.2,位于/lib下。为了指定这个程序,使用GNU连接器参数:dynamic-linker。如下:

    $ ld -dynamic-linker /lib/ld-linux-so.2 -o cpuid -lc cpuid.o

这个才可以保证程序征程运行。它使用ld-linux-so.2动态加载程序加载了libc.so库。

当然也可以使用gcc来自动编译和链接汇编语言和C库函数,gcc自动链接必须的C库。做出如下修改,即可实现:将_start改为main,然后编译:

$ gcc -o cpuid cpuid.s

同样可以运行并且得到相同的结果。

————————第四章完结—————

0 0
原创粉丝点击