这显得很古怪,不过在gcc知道程序员拿这些寄存器做些什么后,这确实能够对gcc的优化操作有所帮助。表5-3中是一些可能会用到的寄存器加载代码及其具体的含义。

表5-3 常用寄存器加载代码说明

代 码

说 明

代 码

说 明

a

使用寄存器eax

m

使用内存地址

b

使用寄存器ebx

o

使用内存地址并可以加偏移值

c

使用寄存器ecx

I

使用常数0~31

d

使用寄存器edx

J

使用常数0~62

S

使用esi

K

使用常数0~255

D

使用edi

L

使用常数0~65535

q

使用动态分配字节可寻址机寄存器(eax、ebx、ecx、或edx)

M

使用常数0~3

r

使用任意动态分配的寄存器

N

使用1字节常数

g

使用通用有效的地址即可(eax、ebx、ecx、edx或内存变量)

O

使用常数0~31

A

使用eax与edx联合(64位)

下面的例子不是让程序员自己指定哪个变量使用哪个寄存器,而是让gcc为程序员选择。

01 asm("leal (%1, %1, 4),

%0"02 : " =r"(y)03 : "0"(x));

第一句汇编语句leal(r1,r2,4),r3语句表示r1+r2*4→r3,。这个例子可以非常快地将x乘5。其中“%0”,“%1”是指gcc自动分配的寄存器。这里“%1”代表输入值x要放入的寄存器,“%0”表示输出值寄存器。输出寄存器代码前一定要加入等于号。如果输入寄存器的代码时0或为空时,则说明使用与相应输出一样的寄存器。所以。如果gcc将r指定为eax的话,那么上面汇编语句的含义即为:“leal(eax,eax,4),eax”。

注意:在执行代码时,如果不希望汇编语句被gcc优化而改变位置,就需要在asm符号后面添加volatile关键词:asm

volatile(……);

或者更详细地说明为:_

_asm_ _ _ _volatile_ _(……);

一、AT&T 格式Linux 汇编语法格式

1.在 AT&T

汇编格式中,寄存器名要加上 '%' 作为前缀;而在 Intel 汇编格式中,寄存器名不需要加前缀。 AT&T

格式

Intel

格式

pushl �x

push eax

2.在 AT&T 汇编格式中,用 '$' 前缀表示一个立即操作数;而在 Intel

汇编格式中,立即数的表示不用带任何前缀。例如:

AT&T

格式

Intel

格式

pushl $1

push 1

AT&T 和 Intel

格式中的源操作数和目标操作数的位置正好相反。在 Intel 汇编格式中,目标操作数在源操作数的左边;而在

AT&T 汇编格式中,目标操作数在源操作数的右边。例如:

AT&T

格式

Intel

格式

addl $1, �x

add eax, 1

在 AT&T

汇编格式中,操作数的字长由操作符的最后一个字母决定,后缀'b'、'w'、'l'分别表示操作数为字节(byte,8

比特)、字(word,16 比特)和长字(long,32比特);而在 Intel 汇编格式中,操作数的字长是用 "byte ptr"

和 "word ptr" 等前缀来表示的。例如:

AT&T

格式

Intel

格式

movb val, %al

mov al, byte ptr val

5.在 AT&T

汇编格式中,绝对转移和调用指令(jump/call)的操作数前要加上'*'作为前缀,而在 Intel 格式中则不需要。

远程转移指令和远程子调用指令的操作码,在

AT&T 汇编格式中为 "ljump" 和 "lcall",而在 Intel 汇编格式中则为 "jmp

far" 和 "call far",即:

AT&T

格式

Intel

格式

ljump $section, $offset

jmp far section:offset

lcall $section, $offset

call far section:offset

与之相应的远程返回指令则为:

AT&T

格式

Intel

格式

lret $stack_adjust

ret far stack_adjust

在 AT&T 汇编格式中,内存操作数的寻址方式是

section:disp(base, index, scale)

而在 Intel 汇编格式中,内存操作数的寻址方式为:

section:[base + index*scale + disp]

由于 Linux 工作在保护模式下,用的是 32

位线性地址,所以在计算地址时不用考虑段基址和偏移量,而是采用如下的地址计算方法:

disp + base + index * scale

下面是一些内存操作数的例子:

AT&T

格式

Intel

格式

movl -4(�p), �x

mov eax, [ebp - 4]

movl array(, �x, 4), �x

mov eax, [eax*4 + array]

movw array(�x, �x, 4), %cx

mov cx, [ebx + 4*eax + array]

movb $4, %fs:(�x)

mov fs:eax, 4

linux内核嵌入式汇编总结(1)

在linux内核中有很多的嵌入式汇编代码。

嵌入汇编的基本格式为:

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

其中”汇编语句”是程序员写汇编指令的地方;”输出寄存器”表示当这段嵌入式汇编执行之后,哪些寄存器用于存放输出数据。这些寄存器会分别对应一个C语言表达式或一个内存地址;“输入寄存器”表示在开始执行汇编代码时,这里指定的一些寄存器中应存放的输入值,它们也分别对应着一个C变量或常数值。下面用例子来说明嵌入式汇编语句的使用方法。

我们在下面列出了一段代码作为例子来详细解说,

01 #define get_seg_byte(seg,addr)

\ 02 ({

\ 03 register char __res;

\ 04 __asm__("push %%fs;

\ 05 mov %%ax, %%fs;

\ 06 movb %%fs: %2, %%al;

\ 07 pop %%fs"

\ 08 :" =a" (__res)

\ 09 :"" (seg),"m" (* (addr)));

\ 10 __res; })

这段10行代码定义了一个嵌入式汇编语言宏函数。通常使用汇编语句最方便的方式是把它们放在一个宏内。用圆括号括住的组合语句(花括号中的语句)可以作为表达式使用,其中最后的变量__res(第10行)是该表达式的输出值。

因为是宏语句,需要在一行上定义,因此这里使用反斜杠'\'将这些语句连成一行。这条宏定义将被替换到宏名称在程序中被引用的地方。第1行定义了宏的名称,也就是宏函数名称get_seg_byte(seg,addr)。第3行定义了一个寄存器变量_

_res。第4行上的_ _asm_

_表示嵌入式语句的开始。从第4行到第7行的4条AT&T格式的汇编语句。 第8行是输出寄存器,这句的含义是在这段代码运行结束后将eax所代表的寄存器的值放入_

_res变量中,作为本函数的输出值,“=a”中的“a”称为加载代码,“=”表示这是输出寄存器。第9行表示在这段代码开始运行时将seg放到eax寄存器中,“”表示使用与上面同个位置的输出相同的寄存器。而(*(addr))表示一个内存偏移地址值。为了在上面汇编语句中使用该地址值,嵌入式汇编程序规定把输入和输出寄存器统一按顺序编号,顺序是从输出寄存器序列从左到右从上到下以“%0”开始,分别记为%0、%1、……%9。因此,输出寄存器的编号是%0(这里只有一个输出寄存器),输出寄存器前一部分(””(seg))的编号是%1,而后部分的编号是%2。上面第6行上的%2即代表(*(addr))这个内存偏移量。

现在我们来研究4~7行上的代码的作用。第一句将fs段寄存器的内容入栈;第二句将eax中的段值赋给fs段寄存器;第三句是fs:(*(addr))所指定的字节放入al寄存器中。当执行完汇编语句后,输出寄存器eax的值将被放入_

_res,作为该宏函数的返回值。

01 asm("cld\n\t"02 "rep\n\t"03 "stol"04 :

05 :

"c"(count-1), "a"(file_value),

"D"(dest)06 :

"�x", "�i");

1~3行这三句是通常的汇编语句,用以清方向位,重复保存值。第4行说明这段嵌入汇编程序没有用到输出寄存器。第5行的含义是:将count-1的值加载到ecx中,dest放到edi中。为什么要让gcc编译程序去做这样的寄存器值的加载,而不让我们自己做呢?因为gcc在它进行寄存器分配时可以进行某些优化工作。例如fill_value值可能已经在eax中。如果是在一个循环语句中的话,gcc就可能在整个循环操作中保留eax,这样就可以在每次循环中少用一个movel语句。最后一行的作用是告诉gcc这些寄存器中的值已经改变了。

通过上面分析,我们知道,宏名称中的seg代表一指定的内存段值,而addr表示一内存偏移地址量。到现在为止,我们应该很清楚这段程序的功能了吧!该宏函数的功能是从指定段和偏移值的内存地址处取一个字节。再看下一个例子。

stol函数在linux下使用,Linux下ATT汇编语法简介一相关推荐

  1. att汇编教程 linux,ATT 汇编语法

    6 个段寄存器:%cs(code),%ds(data),%ss(stack), %es,%fs,%gs; 3 个控制寄存器:%cr0,%cr2,%cr3; 6 个 debug 寄存器:%db0,%db ...

  2. linux中probe函数传递参数的寻找(下)

    点击打开链接 linux中probe函数传递参数的寻找(下) 通过追寻driver的脚步,我们有了努力的方向:只有找到spi_bus_type的填充device即可,下面该从device去打通,当两个 ...

  3. linux getline参数,Linux下的getline函数

    最近在做国嵌的mp3项目,在mp3主控程序中用到了这个函数,挺好使的,在这里记录一下.注意是linux下的,不是C++中的. 函数原型 ssize_t getline(char **lineptr, ...

  4. Linux下的ATT语法(即GNU as 汇编语法)入门

    学习这么长时间,一直在C语言这一层面上钻研和打拼,日积月累,很多关于C的疑惑在书本和资料中都难以找到答案.程序员是追求完美的一个种群,其头 脑中哪怕是存在一点点的思维黑洞都会让其坐卧不宁.不久前在it ...

  5. Linux中/proc目录下文件详解

    Linux中/proc目录下文件详解(一) 声明:可以自由转载本文,但请务必保留本文的完整性. 作者:张子坚 email:zhangzijian@163.com 说明:本文所涉及示例均在fedora ...

  6. 如何在Windows下使用Linux系统来编译和运行程序?

    很多开发人员都有这样的疑问:自己平时是在Windows下面办公的,而自己编写的程序的运行环境又是Linux的,如何从Windows切换到Linux呢?是不是要专门到Linux机器上去编写代码呢? 实际 ...

  7. linux 有线网卡,linux下有线网卡出现ADDRCONF(NETDEV_UP): eth0: link is not ready的解决方法...

    一.背景 2018年5月24日,笔者的pc已经连续运转两天了,突然要使用有线网卡,却发现有线网卡无法正常工作,于是查看了一下内核日志: r8169 0000:05:00.0 eth0: link do ...

  8. osg linux 环境配置,Linux环境下jdk1.8的下载与安装

    Linux环境下jdk1.8的下载与安装 1.下载 Oracle官网下载相应的版本,官网地址:https://www.oracle.com/java/technologies/javase/javas ...

  9. linux闲话FHS标准下linux目录结构

    2019独角兽企业重金招聘Python工程师标准>>> 1.闲话         2011年10月24日收到了秒针的OfferLetter并决定加入之后,就开始认真学习linux.坦 ...

最新文章

  1. MAC使用终端DISKUTIL命令给U盘分区(解决window优盘只有200M)
  2. ERROR: No query specified(Mysql数据库报错)
  3. r语言 林元震_科学网—R语言简介 - 林元震的博文
  4. 【引用】jQuery 选择器
  5. tomcat6的项目能直接在tomcat7上用吗_极尽人性化的设计: 能“隐形”的笔记本电脑支架...
  6. 年薪30W的软件测试“老司机”工作经验
  7. ​最高要价 8888元,小米 11 邀请函现身闲鱼;荣耀与微软签署全球 PC 合作协议;Xfce 4.16 发布|极客头条...
  8. network of emergency contacts---BFS
  9. Hypermesh-优化案例学习笔记-cclip
  10. Servlet 运行工作原理详解
  11. 网盘共享文件有病毒吗?
  12. Camera+收入超500万美金,VPlayer能否击败其神话?
  13. 4.4-软件开发中,“UI设计图”的作用与绘制方法说明
  14. iOS开发之Crash分析,以及收集
  15. 键盘上每个键作用!!! (史上最全的)
  16. 企业员工信息管理系统(C语言编程)
  17. JUnit version 3.8 or later expected
  18. wlan从入门到精通第四期WLAN常用概念
  19. 【创建petstore数据库与表】
  20. 软件架构设计---软件架构概述

热门文章

  1. Java 输出指定目录下的所有文件
  2. MySql数据库常用命令宝典
  3. ios android 字体颜色,iOS-修改导航栏文字字体和颜色
  4. Python 小白从零开始 PyQt5 项目实战(7)折叠侧边栏的实现
  5. 计算机电路基础答案,计算机电路基础模拟试卷答案(B)
  6. opencv glob 内存溢出异常
  7. mysql添加用户权限报1064 - You have an error in your SQL syntax问题解决
  8. Python类的构造方法__init__(self)和析构函数__del__详解
  9. print的小白用法
  10. meta http-equiv=X-UA-Compatible content=IE=edge,chrome=1 /