Linux中的汇编简介

GNU as汇编语法

GNU汇编语法使用的是AT&T汇编它和Intel汇编的语法主要有以下一些不同:

  • AT&T汇编中的立即操作数前面要加上‘$‘,寄存器操作数名前要加上百分号‘%‘,绝对跳转操作数前要加上‘*‘,Intel的语法均不包含这些符号;
  • AT&T语法与Intel语法中使用的源操作数和目的操作数顺序正好相反,AT&T的源操作数和目的操作数是从左到右,Intel语法是从右到左,例如add eax, 4在AT&T语法中是addl $4, %eax;
  • AT&T语法中内存操作数长度由操作码的最后一位字符来确定,操作码后缀有b/w/l分别代表内存引用宽度为8位,16位和32位,Intel语法则通过在内存操作数前使用前缀byte ptr,word ptr和dword ptr来达到此目的。例如Intel中的mov al, byte ptr foo对应AT&T中的语句为movb $foo, %al;
  • AT&T语法中立即跳转和调用为ljmp/lcall $section, $offset,而Intel中的是jmp/call far section:offset,AT&T中的返回指令lret $stack-adjust对应Intel的ret far stack-adjust;
  • AT&T汇编器不支持多代码段程序,类UNIX系统要求所有代码在一个段中;

预处理:as汇编器能对汇编语言进行简单的预处理,包括删除多余的空格和制表符,删除注释语句,把字符常数转换为对应的数值,但此预处理不能处理宏,也没有处理包含文件的功能,如果需要这些功能,可以使用gcc的预处理器cpp来实现。

符号:GNU汇编语言中的符号是由字符组成的标识符,组成符号的字符包含大小写字母,数字和_.$三个字符,符号不允许以数字开始,且区分大小写。在汇编程序中符号长度没有限制,符号使用空格来界定开始和结束。语句以换行符或者行分割符(;)作为结束,文件最后必须以换行符作为结束,语句有0个或多个标号开始(Label),后面可跟随一个确定语句类型的关键符号,标号由符号后面跟随一个冒号构成,关键符号确定了余下部分语句的语义,如果关键符号以.开始,那么当前语句就是一个汇编命令,如果关键符号以字母开始,那么当前语句就是一条汇编语言指令语句,一it哦啊语句的通用格式为:

标号:汇编命令     注释语句
或者
标号:指令助记符 操作数1, 操作数2     注释语句

常数:常数是一个数字,分为字符常数和数字常数两类,字符常数分为单个字符和字符串,数字常数分为整数和浮点数。汇编语言的单个字符表示一版为在该字符前加上单引号,而字符串需要添加双引号。

指令:指令是CPU执行的操作,通常指令称为操作码,操作数是指令操作的对象,而地址是指令数据在内存中的位置,一条指令语句一版包括:标号,操作码(指令助记符),操作数,注释。

操作数:操作数包含立即操作数,寄存器和内存。间接操作数含有实际操作数的地址值,AT&T语法通过在操作数前加上*来表示间接操作数,只有跳转和调用指令才能使用间接操作数。立即操作数前面需要加上$符号,寄存器名前面需要加上%符号,内存操作数由变量名或者含有变量地址的寄存器指定,变量名隐含指出了变量的地址,并指示cpu引用改地址内存处的内容。

操作码:AT&T语法中指令操作码最后一个字符用来指明操作数的宽度,字符b,w和l分别制定byte,word和long类型的操作数。如果指令名没有带字符后缀,并且指定语句中不含内存操作数,那么as汇编器会根据寄存器操作数来尝试确定操作数宽度。操作码前缀用于修饰随后的操作码,他们用于重复字符串指令,提供区覆盖,执行总线锁定操作或者指定操作数和地址宽度。

内存引用:AT&T语法的间接内存引用形式为section:disp(base, index, scale),其中base和index是32位的基寄存器和索引寄存器,disp是可选的偏移值,scale是比例因子,scale乘上index用来表示操作数地址,section为内存操作数指定的段寄存器。

movl var, %eax                 #把内存地址var处的内容放入寄存器%eax
movl %cs:var, %eax             #把代码段中的内存地址var处的内容放入%eax
movb $0xa0, %es:(%ebx)         #把0xa0放入到es段的%ebx指定的偏移处
movl $var, %eax                #把var的地址放入%eax
movl array(%esi), %eax         #把array+%esi内存地址的内容放入eax
movl (%ebx, %esi, 4), %eax     #把ebx+esi*4地址处的内容放到eax
movl array(%ebx, %esi, 4), %eax#把array+ebx+esi*4地址的内容放到eax
movl -4(%ebp), %eax            #把ebp-4地址处的内容放到eax

指令跳转:跳转指令用于把执行点转移到程序的另外的位置执行,跳转的目的位置通常用一个标号来表示。jmp是无条件跳转,可分为直接跳转和间接跳转,直接跳转语句的写法是给出跳转目标处的标号,间接跳转语句的写法是使用*作为操作指示符的前缀字符。

段:段用于表示一个地址范围,它主要用来表示编译器生成的目标文件中的不同的信息区域。例如代码段,数据段,bss段。

符号:符号有很多作用,可以用来命名对象,连接器通过符号执行链接操作,调试器利用符号进行调试。标号是后面接着一个冒号的符号,该符号用来表示代码当前的位置。特殊符号.用来表示汇编的当前位置。除了名字之外每个符号都有值和类型属性。符号的值通常是32位的,链接器会对未定义的符号值做特殊处理,如果未定义的符号值为0则表示该符号在此汇编程序中没有定义,链接器会尝试使用其他链接的文件来确定此符号值,

as汇编器

as汇编器的命令行格式为: as [选项] [-o objfile] [srcfile.s],如果没有指定输出文件名,会默认输出a.out文件。可以再as命令行上给出0个或多个输入文件名,as会按照从左到右的顺序读取这些文件中的内容,在命令行上的参数如果没有实际意义将会被当做输入文件名看待,如果命令行上没有任何文件名,那么as将会试图从终端读取输入文件内容。

as的输出文件:由输入的汇编文件编译生成的二进制文件,目标文件最终作为连接器ld的输入文件。目标文件中包含汇编代码,协助ld产生可执行文件的信息,以及用于调试的符号信息。

内联汇编

内联汇编的基本格式为:

asm("汇编语句"
      : 输出寄存器
      : 输入寄存器
      : 会被修改的寄存器)

除了汇编语句是必须的的以外,其他若不使用都可以省略。其中asm是内联汇编的关键词,汇编语句用于编写汇编指令,输出寄存器表示当这段汇编语句执行完之后,哪些寄存器用于存放输出数据,输入寄存器表示开始执行代码时,制定某些寄存器中应该放入的输入值,会被修改的寄存器表示对列出的寄存器中的值进行了修改。

常用的寄存器加载代码

代码   说明 代码    说明
a 使用寄存器eax m 使用内存地址
b 使用寄存器ebx o 使用内存地址并且可以加偏移值
c 使用寄存器ecx I 使用常数0~31
d 使用寄存器edx J 使用常数0~63
S 使用esi K 使用常数0~255
D 使用edi L 使用常数0~65535
q 使用动态分配字节可寻址寄存器 M 使用常数0~3
r 使用任意动态分配寄存器 N 使用1字节常数
g 使用通用有效地址 O 使用常数0~31
A 使用eax和edx联合 = 输出操作数,输出值替换前值
+ 表示操作数可读可写 & 在使用完操作数之前内容会被修改

在执行代码时,如果不希望汇编语句被gcc优化,需要在asm符号后面添加关键字volatile。关键字volatile也可以放在函数名前来修饰函数,用来通知gcc该函数不会返回。

时间: 2025-01-02 15:48:58

Linux中的汇编简介的相关文章

Linux中Mysql的简介和安装

MySQL 简介 点击查看MySQL官方网站 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,后来被Sun公司收购,Sun公司后来又被Oracle公司收购,目前属于Oracle旗下产品 开源 免费 不要钱 使用范围广,跨平台支持性好,提供了多种语言调用的 API 是学习数据库开发的首选 查看数据库排名:https://db-engines.com/en/ranking 特点 使用C和C++编写,并使用了多种编译器进行测试,保证源代码的可移植性 支持多种操作系统,如Linux

Linux中定时任务cron简介

1.1 特殊权限u+s /o+t [[email protected] ~]# ls -ld /bin/ls /usr/bin/passwd /tmp/ /usr/bin/locate -rwxr-xr-x. 1 root root 117048 Mar 23 2017 /bin/ls drwxrwxrwt. 3 root root 4096 Jul 25 16:27 /tmp/ -rwx--s--x. 1 root slocate 38464 Mar 12 2015 /usr/bin/loca

Linux中的IO复用接口简介(文件监视?)

I/O复用是Linux中的I/O模型之一.所谓I/O复用,指的是进程预先告诉内核,使得内核一旦发现进程指定的一个或多个I/O条件就绪,就通知进程进行处理,从而不会在单个I/O上导致阻塞. 在Linux中,提供了select.poll.epoll三类接口来实现I/O复用. select函数接口 select中主要就是一个select函数,用于监听指定事件的发生,原型如下: 12345 #include<sys/select.h>#include<sys/time.h>int sele

linux中的strings命令简介

摘自:http://blog.csdn.net/stpeace/article/details/46641069 linux中的strings命令简介 在linux下搞软件开发的朋友, 几乎没有不知道strings命令的.我们先用man strings来看看: strings - print the strings of printable characters in files. 意思是, 打印文件中可打印的字符.  我来补充一下吧, 这个文件可以是文本文件(test.c), 可执行文件(te

linux中的strings命令简介2

摘自:http://blog.csdn.net/stpeace/article/details/46641069 linux中的strings命令简介 之前我们聊过linux strings的用法和用途, 但据我了解, 还有部分朋友并不常用strings, 这是个不好的习惯. 所以, 本文继续啰嗦一下strings命令. 在软件开发中, 我们经常需要修改代码, 并生成静态库.动态库或者可执行文件, 有时候, 工程太大, 那怎样确定自己改动的代码正确编译到库中去了呢? 用strings命令吧!  

linux内核分析第四周-使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

本周作业的主要内容就是采用gcc嵌入汇编的方式调用system call.系统调用其实就是操作系统提供的服务.我们平时编写的程序,如果仅仅是数值计算,那么所有的过程都是在用户态完成的,但是我们想将变量打印在屏幕上,就必须调用printf,而printf这个函数内部就使用了write这个系统调用.操作系统之所以以system call的方式提供服务,是因为如果程序员能够任意操作OS所有的资源,那么将无比危险,所以OS设计出了内核态和用户态. 我们平时编程都是在用户态下,如果我们想要调用系统资源,那

Linux中的task,process, thread 简介

本文的主要目的是介绍在Linux内核中,task,process, thread这3个名字之间的区别和联系.并且和WINDOWS中的相应观念进行比较.如果你已经很清楚了,那么就不用往下看了. LINUX版本:2.6.18ARCH: X86 首先要明确的是,按照LKD 2里面的说法,LINUX和其他OS 比如WINDOWS, SOLARIS之间一个很大的不同是没有严格定义的线程(thread).那么你也许会问,如果LINUX中没有线程,那么如何来表示类似WINDOWS 线程的那种执行观念呢?答案是

linux中的strip命令简介------给文件脱衣服

转载于:http://blog.csdn.net/stpeace/article/details/47090255 作为一名linux开发人员, 如果没有听说过strip命令, 那是很不应该的. strip这个单词, 大家应该早就学过了, 你就记住是脱衣服就行了, 别的不要多想. 在linux中, strip也有脱衣服的含义, 具体就是从特定文件中剥掉一些符号信息和调试信息. 我们来看main.c文件: [cpp] view plain copy print? #include <stdio.h

解析Linux中的VFS文件系统之文件系统的来源与简介

最近挂载了N多的文件系统,大致了不同文件系统的相应特性及挂载方式,却还是对Linux的文件系统没有从源码方面去了解.不求甚解确实不好不好. 于是借鉴一些大牛的博客及自己的理解,总结了博客系列: 一.VFS是什么: VFS是Linux中的一个虚拟文件文件系统,也称为虚拟文件系统交换层(Virtual Filesystem Switch),是一种软件机制.它为应用程序员提供一层抽象,屏蔽底层各种文件系统的差异.如下图所示: 引入文件系统的目的是:为了屏蔽各种文件系统的差异 (1)VFS对实际文件系统