Linux汇编初识

来源:互联网 发布:win10最详细优化设置 编辑:程序博客网 时间:2024/06/04 00:54

linux汇编  

2011-06-11 20:29:02|  分类:x86与arm |  标签:movl  汇编器  linux  代码  att  |举报|字号 订阅


        由于我喜欢一些底层的东西,不由得想弄一下AT&T格式的汇编。linux 内核中的启动部分就有用该汇编代码完成的。
程序员学习一门新的语言,一般的思维就是现实现一下输出“hello world!”。下面就拿这个下的程序来说明ATT汇编的特点吧。
   
汇编的优点:
1,能够直接访问与硬件相关的存储器或 I/O 端口;
2,能够不受编译器的限制,对生成的二进制代码进行完全的控制;
3,能够对关键代码进行更准确的控制,避免因线程共同访问或者硬件设备共享引起的死锁;
4,能够根据特定的应用对代码做最佳的优化,提高运行速度;
5,能够最大限度地发挥硬件的功能。

汇编的缺点。
1,编写的代码非常难懂,不好维护;
2,很容易产生 bug,难于调试;
3,只能针对特定的体系结构和处理器进行优化;
4,开发效率很低,时间长且单调。

Linux 下用汇编语言编写的代码具有两种不同的形式。
1,第一种是完全的汇编代码,指的是整个程序全部用汇编语言编写。
2,第二种是内嵌的汇编代码,指的是可以嵌入到 C 语言程序中的汇编代码片段。

一,ATT汇编程序

# hello.s  ---->  intel汇编的注释用的; 而ATT用的## display a string "Hello, world." .section .rodatamsg: .ascii "Hello, world.\n" .section .text.globl _start_start:

  movl $2, %eax  #调用fork系统调用 int $0x80

   movl $4, %eax # system call  系统调用号(sys_write) movl $1, %ebx # file descriptor 参数一:文件描述符(stdout) movl $msg, %ecx # string address  参数二:要显示的字符串 movl $14, %edx # string length  参数三:字符串长度 int $0x80          # 调用内核功能 movl $1, %eax     # 系统调用号(sys_exit) movl $0, %ebx     # 参数一:退出代码 int $0x80       # 调用内核功能


 wanny@wanny-C-Notebook-XXXX:~$ as hello.s -o hello.o
wanny@wanny-C-Notebook-XXXX:~$ ld hello.o -o hello
wanny@wanny-C-Notebook-XXXX:~$ ./hello
Hello, world.
Hello, world.  
二,Linux 汇编工具
           Linux 平台下的汇编工具虽然种类很多,但同 DOS/Windows 一样,最基本的仍然
是汇编器、连接器和调试器。

2.1.汇编器
汇编器(assembler)的作用是将用汇编语言编写的源程序转换成二进制形式的目标
代码。Linux 平台的标准汇编器是 GAS,它是 GCC 所依赖的后台汇编工具,通常
包含在 binutils 软件包中。GAS 使用标准的 AT&T 汇编语法,可以用来汇编用
AT&T 格式编写的程序:

例如:
 wangzhe@wangzhe-laptop:~$ as -o hello.o hello.s

Linux 平台上另一个经常用到的汇编器是 nasm,它提供了很好的宏指令功能,并
能够支持相当多的目标代码格式,包括 bin、a.out、coff、elf、rdf 等。NASM 采用
的是人工编写的语法分析器,因而执行速度要比 GAS 快很多,更重要的是它使用
的是 Intel 汇编语法,可以用来编译用 Intel 语法格式编写的汇编程序:

例如:
wangzhe@wangzhe-laptop:~$ nasm -f elf hello2.asm

2.2 链接器
由汇编器产生的目标代码是不能直接在计算机上运行的,它必须经过链接器的处理
才能生成可执行代码。链接器通常用来将多个目标代码连接成一个可执行代码,这
样可以先将整个程序分成几个模块来单独开发,然后才将它们组合(链接)成一个应
用程序。 Linux 使用 ld 作为标准的链接程序,它同样也包含在 binutils 软件包中。
汇编程序在成功通过 GAS 或 NASM 的编译并生成目标代码后,就可以使用 ld 将
其链接成可执行程序了:


例如:
wangzhe@wangzhe-laptop:~$ ld -o hello hello.o

3.调试器
有人说程序不是编出来而是调出来的,足见调试在软件开发中的重要作用,在用汇
编语言编写程序时尤其如此。Linux 下调试汇编代码既可以用 GDB、DDD 这类通
用的调试器,也可以使用专门用来调试汇编代码的 ALD(Assembly Language
Debugger)。
从调试的角度来看,使用 GAS 的好处是可以在生成的目标代码中包含符号表
(symbol table),这样就可以使用 GDB 和 DDD 来进行源码级的调试了。要在生成
的可执行程序中包含符号表,可以采用下面的方式进行编译和链接:


例如:
wangzhe@wangzhe-laptop:~$ as --gstabs -o hello.o hello.s
wangzhe@wangzhe-laptop:~$ ld -o hello hello.o
wangzhe@wangzhe-laptop:gdb -q hello

三,系统调用
          即便是最简单的汇编程序,也难免要用到诸如输入、输出以及退出等操作,而要进
行这些操作则需要调用操作系统所提供的服务,也就是系统调用。除非你的程序只完成
加减乘除等数学运算,否则将很难避免使用系统调用,事实上除了系统调用不同之外,各种
操作系统的汇编编程往往都是很类似的。

          在 Linux 平台下有两种方式来使用系统调用:利用封装后的 C 库(libc)或者通过
汇编直接调用。其中通过汇编语言来直接调用系统调用,是最高效地使用 Linux 内核
服务的方法,因为最终生成的程序不需要与任何库进行链接,而是直接和内核通信。
           和 DOS 一样,Linux 下的系统调用也是通过中断(int 0x80)来实现的。在执行 int
80 指令时,寄存器 eax 中存放的是系统调用的功能号,而传给系统调用的参数则必须按
顺序放到寄存器 ebx,ecx,edx,esi,edi 中,当系统调用完成之后,返回值可以在寄存器 eax
 中获得。
          所有的系统调用功能号都可以在文件 /usr/include/bits/syscall.h 中找到,为了便
于使用,它们是用 SYS_<name> 这样的宏来定义的,如 SYS_write、SYS_exit 等。例
如,经常用到的 write 函数是如下定义的:
ssize_t write(int fd, const void *buf, size_t count);
该函数的功能最终是通过 SYS_write 这一系统调用来实现的。根据上面的约定,参
数 fb、buf 和 count 分别存在寄存器 ebx、ecx 和 edx 中,而系统调用号 SYS_write
则放在寄存器 eax 中,当 int 0x80 指令执行完毕后,返回值可以从寄存器 eax 中获得。
或许你已经发现,在进行系统调用时至多只有 5 个寄存器能够用来保存参数,难道
所有系统调用的参数个数都不超过 5 吗?当然不是,例如 mmap 函数就有 6 个参
数,这些参数最后都需要传递给系统调用 SYS_mmap:
整理
void * mmap(void *start, size_t length, int prot , int flags, int fd,
off_t offset);
当一个系统调用所需的参数个数大于 5 时,执行 int 0x80 指令时仍需将系统调用功能号保存
在寄存器 eax 中,所不同的只是全部参数应该依次放在一块连续的内存区域里,同时在寄存器
ebx 中保存指向该内存区域的指针。系统调用完成之后,返回值仍将保存在寄存器 eax 中。
由于只是需要一块连续的内存区域来保存系统调用的参数,因此完全可以像普通的
函数调用一样使用栈(stack)来传递系统调用所需的参数。但要注意一点,Linux 采
用的是 C 语言的调用模式,这就意味着所有参数必须以相反的顺序进栈,即最后
一个参数先入栈,而第一个参数则最后入栈。如果采用栈来传递系统调用所需的参
数,在执行 int 0x80 指令时还应该将栈指针的当前值复制到寄存器 ebx 中。


四,C语言中内联汇编
          例如:
#include <stdio.h>

int main(void)
{
   int a = 10, b = 0;
   __asm__ __volatile__("movl %1, %%eax;"
   "movl %%eax, %0;"
   :"=r"(b) /* 输出 */
   :"r"(a)  /* 输入 */
   :"%eax");/* 不受影响的寄存器 */
   printf("Result: %d, %d\n", a, b);
}

通常嵌入到 C 代码中的汇编语句很难做到与其它部分没有任何关系,因此更多时
候需要用到完整的内联汇编格式:
__asm__("asm statements" : outputs : inputs : registers-modified);
插入到 C 代码中的汇编语句是以":"分隔的四个部分,其中第一部分就是汇编代码

本身,通常称为指令部,其格式和在汇编语言中使用的


原文地址:
http://blog.163.com/zhe_wang_2009/blog/static/172282121201151175619458/
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 微信号不是手机号不知道密码怎么办 手机发短信说程序发生错误怎么办 派派游戏崇物等级低怎么办 轻微事故没有报警后面有问题怎么办 苹果6sp手机接电话声音小怎么办 用手机号办的移动宽带到期了怎么办 联通忘了宽带的用户名和密码怎么办 宽带联通移机附近没有端口怎么办 电信卡怎么改服务密码忘记了怎么办 路由器重置宽带账号密码忘了怎么办 重置路由器后不知道宽带密码怎么办 欠费后重新缴费宽带连接不了怎么办 华硕路由器忘记账号密码忘了怎么办 光纤猫光信号闪红灯不能上网怎么办 被传销洗了脑的人怎么办 辞职了评职称年度考核表怎么办 我是饭店饭店欠供货商的钱多怎么办 mac电脑ps卡住了点不了怎么办 高考自愿民族栏要改为民族怎么办 法院拆消裁定后再审有错怎么办 重定向语句前面有文件路劲怎么办 您上传的图片大小超过3M怎么办 两个人打架被拍视频上传了怎么办 小米手机打开后一直出现英文怎么办 百度云分享文件含有违规内容怎么办 百度网盘下载说本地空间不足怎么办 绘声绘影X9将滤镜拖到视频怎么办 苹果手机中间的按钮没用了怎么办? 图片怎么发的在百度里面应该怎么办 学java刚看的视频就忘了怎么办 qq上传照片一直显示排队中怎么办 微信支付不小心重复付款怎么办 学习通上传视频时 文件过大怎么办 电脑死机了怎么办 也不能关机了 还没发货淘宝退款卖家不处理怎么办 还没发货申请退款卖家不处理怎么办 快递写错电话被更改收货信息怎么办 货在派送中快递地址填错了怎么办 老板损坏了你保管的器材怎么办 闲鱼买家说不合适要退货怎么办 日本邮便局的单号我忘了怎么办