关于AT&T汇编语言,网上有许多语法介绍,大家可以移步参考。我这里主要介绍几个汇编实例,如何在linux系统编译,以及浮点数的输出。
一. 一个简单的汇编实例:输出hello,world!
.section .data #以下为数据段
output: #标签(变量名):关联了当前地址
.ascii "hello,world!\n"
len = . - output #定义字符串的长度
.section .text #以下为代码段
.globl _start #起始的函数名
_start:
movl $4, %eax #系统调用值 $4—输出(write) $4---立即数(常量)
movl $1, %ebx # I/O设备:0-标准输入 1-标准输出 2-错误输出
movl $output,%ecx #输出内容的地址
movl $len,%edx #输出内容的长度
int $0x80 #Linux 0x080号系统调用
movl $1,%eax #系统调用值 $1—退出(exit)
movl $0,%ebx #退出码 可以用echo $? 查看
int $0x80 #Linux系统调用
二 . 如何运行AT&T代码
将代码存为helloworld.s,在命令行中输入:
第一行命令(as):将helloworld.s编译成二进制文件helloworld.o;
第二行命令(ld):将helloworld.o链接成可执行文件helloworld;
第三行命令:运行文件helloworld。
三. 调用C语言函数库输出字符串以及整型数
AT&T汇编语言允许调用C语言的函数库。下面介绍调用C的printf()函数输出字符串和整型数,
代码如下:
.section .data
output:
.ascii"The number is %d\n"
.section .bss #缓冲数据区,存放未初始化数据
.lcomm buffer,18 #声明18个字节的缓冲区
.section .text
.globl _start
_start:
pushl $520 #$520为立即数,对应输出中的%d
pushl $output
call printf #调用C语言printf函数
addl $8,%esp #堆栈指针加8
pushl $0 #退出码
call exit #调用C语言函数exit
输出结果:
注意:调用C语言函数,编译和链接过程都与上面的例子不太一样。链接的时候要指定C语言动态链接库。假设将文件命名为print.s。(由于命令比较长,下面直接以代码的形式给出)
as --32 -o print.o print.s
ld -dynamic-linker /lib/ld-linux.so.2 -lc -m elf_i386 -o print print.o
./print
(1)–32表示将目标代码编译成ia-32代码格式;
(2)-m elf_i386表示生成32 elf位elf格式文件;
(3)-dynamic-linker /lib/ld-linux.so.2指定C语言的动态链接库;
(4)-lc 使用gnu连接器的-l参数是为了链接libc.so文件,-c是指定库名称。
四. 浮点数的运算和利用printf输出
用一个题目来体现吧:
.section .data
array:
.int 12,4,6,7,80,34,54,46,3,23 #声明一个类型为int的数组array
str1:
.ascii"The mean is: %f\n"
str2:
.ascii"The minimum is: %d\n"
value:
.int 12 #值为12的int型变量
value2:
.int 10 #值为10的int型变量
.section .bss
.lcomm buffer,20
.section .text
.globl _start
_start:
finit #初始化浮点数寄存器st[x]
fildl value #赋值,st[0] = 12,我们用st[0]存储和(浮点数形式)
movl $0,%edi #edi 相当于下标i
movl array(,%edi,4),%eax #可以理解为eax = array[i]
movl %eax,%ebx #ebx = eax,用ebx寄存器存最小值
start_loop:
cmpl $23,%eax #比较立即数23和eax寄存器内的值
je exit_loop #je 指令,最近一个运算结果若为相等,则跳转至exit_loop函数
incl %edi #i++
movl array(,%edi,4),%eax #eax = array[i]
fiadd array(,%edi,4) #st[0] = st[0] + array[i],浮点数加法指令
cmpl %eax,%ebx #比较指令
jle start_loop #jle指令,如果eax>=ebx,就跳转至start_loop函数
movl %eax,%ebx #eax
解释:浮点数的存储很特殊,必须使用专门的浮点数寄存器st[0],st[1]…浮点数有专门的栈,最后一个入栈的元素存放在st[0],同时,st[0]也是默认的运算寄存器。浮点数加减乘除都没有多余的参数,默认就是对st[0]。赋值时,我们可以直接将整数赋值给浮点数寄存器,会自动转为浮点数格式,但是不能用立即数进行赋值。
这道题实际是利用一个简单的循环,通过比较找到最小的数,以及累加得到浮点数类型的和,再用浮点数除法得到均值。相信有过汇编语言编程经历的同学都是可以看懂的。运行结果如下:
五. 总结
写这篇博客的目的主要是记录一下学习的过程。如果能给一些初学的同学一点启发,实在是我的荣幸。由于博主本人接触汇编语言时间也不久,很多知识也是自己摸索得到的,难免会有些不准确的描述,欢迎大佬们指正。