Chinaunix首页 | 论坛 | 博客
  • 博客访问: 705361
  • 博文数量: 140
  • 博客积分: 8196
  • 博客等级: 中将
  • 技术积分: 1350
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-16 19:53
文章分类

全部博文(140)

文章存档

2011年(2)

2010年(2)

2009年(2)

2008年(20)

2007年(52)

2006年(62)

分类: C/C++

2006-08-23 11:44:29

cpuid.s程序使用Linux的系统调用(int $0x80)来显示字符串和退出程序,如果系统中装有C语言函数库的话,也可以使用C函数来达到同样的目的。
 
本文介绍如何在汇编语言中使用C语言的库函数,例子程序是那个显示CPU厂商信息的cpuid.s的改进版本cpuid2.s。在cpuid2.s中使用了标准C库的printf和exit函数来替换Linux的系统调用。例程如下:
 
#cpuid2.s -- Using C labrary calls
.section .data
output:
        .asciz "The processor Vender is '%s'\n"
.section .bss
        .lcomm buffer, 12
.section .text
.globl _start
_start:
        movl $0, %eax
        cpuid
        movl $buffer, %edi
        movl %ebx, (%edi)   //含义同cpuid.s,向%edi所指向的buffer内存
        movl %edx, 4(%edi)  //位置写入3个寄存器的内容,这3个寄存器存储了
        movl %ecx, 8(%edi)  //CPU厂商信息的字符串(12字节)
        pushl $buffer       //将buffer和output入栈,为printf提供参数
        pushl $output
        call printf         //调用C的printf函数
        addl $8, %esp       //将堆栈指针回滚8个字节,达到清除printf参数
                            //的目的
        pushl $0
        call exit
 
其中,.asciz是在定义字符串的时侯在字符串结尾加上空字符(即C语言的\0),这样做的目的是为了让printf能读懂字符串。.lcomm是在本地内存区域中声明固定长度的未初始化数据,这里初始化了12个字节的空间。
 
程序里buffer和output内存位置的内容是要向printf传递的参数值,一个是"The processor Vender is '%s'\n"字符串,另外一个是由cpuid返回结果(在ebx,edx,ecx三个寄存器中)填充的buffer。需要通过堆栈来传递参数,所以在程序中使用 
 
pushl $buffer      
pushl $output
 
将参数入栈,printf获取参数是自右向左,即先buffer后output,所以要把buffer后入栈。参数入栈之后,用call指令调用printf。exit的情况同上,使用了一个参数--常数0。
 
然后汇编连接程序:
 
$as -o cpuid2.o cpuid2.s
$ld -o cpuid2 cpuid2.o
cpuid2.o: In function '_start':
cpuid2.o(.text+0x3f): undefined reference to 'printf'
cpuid2.o(.text+0x46): undefined reference to 'exit'
$
 
汇编的时侯没有问题,但是按原来的方式连接程序的时侯出现错误了。原因在于ld不会自己去寻找C库,必须手动指定C库文件来连接程序。使用命令-l,此-l和gcc的-l基本相同,-l的参数是库的名字(比如libc.so中c就是库的名字)而不是库文件的全名
 
$ld -o cpuid2 -lc cpuid2.o
$./cpuid2
bash: ./cpuid2: No such file or directory
$
 
连接没有问题,但是运行程序的时侯又出问题了。这是因为由于采用了动态连接的方式,所以C函数没有包含在可执行程序中,需要由另外的程序在运行时加载,ld不知道这个程序在哪里,所以我们还得手动指定
 
$ld -dynamic-linker /lib/ld-linux.so.2 -lc -o cpuid2 cpuid2.o
$./cpuid2
The processor Vender is 'GenuineIntel'
$
 
运行成功了,其中ld-linux.so.2是动态加载器,用来查找libc.so
 
总结:
如果汇编程序中使用了外部的C库函数,汇编连接程序的时侯需要指定相关的参数以连接库,相比之下GCC编译C程序的时侯很多事情都是自动完成的,要方便很多。
 
阅读(3582) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~