stol函数在linux下使用,Linux下ATT汇编语法简介一
这显得很古怪,不过在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汇编语法简介一相关推荐
- att汇编教程 linux,ATT 汇编语法
6 个段寄存器:%cs(code),%ds(data),%ss(stack), %es,%fs,%gs; 3 个控制寄存器:%cr0,%cr2,%cr3; 6 个 debug 寄存器:%db0,%db ...
- linux中probe函数传递参数的寻找(下)
点击打开链接 linux中probe函数传递参数的寻找(下) 通过追寻driver的脚步,我们有了努力的方向:只有找到spi_bus_type的填充device即可,下面该从device去打通,当两个 ...
- linux getline参数,Linux下的getline函数
最近在做国嵌的mp3项目,在mp3主控程序中用到了这个函数,挺好使的,在这里记录一下.注意是linux下的,不是C++中的. 函数原型 ssize_t getline(char **lineptr, ...
- Linux下的ATT语法(即GNU as 汇编语法)入门
学习这么长时间,一直在C语言这一层面上钻研和打拼,日积月累,很多关于C的疑惑在书本和资料中都难以找到答案.程序员是追求完美的一个种群,其头 脑中哪怕是存在一点点的思维黑洞都会让其坐卧不宁.不久前在it ...
- Linux中/proc目录下文件详解
Linux中/proc目录下文件详解(一) 声明:可以自由转载本文,但请务必保留本文的完整性. 作者:张子坚 email:zhangzijian@163.com 说明:本文所涉及示例均在fedora ...
- 如何在Windows下使用Linux系统来编译和运行程序?
很多开发人员都有这样的疑问:自己平时是在Windows下面办公的,而自己编写的程序的运行环境又是Linux的,如何从Windows切换到Linux呢?是不是要专门到Linux机器上去编写代码呢? 实际 ...
- linux 有线网卡,linux下有线网卡出现ADDRCONF(NETDEV_UP): eth0: link is not ready的解决方法...
一.背景 2018年5月24日,笔者的pc已经连续运转两天了,突然要使用有线网卡,却发现有线网卡无法正常工作,于是查看了一下内核日志: r8169 0000:05:00.0 eth0: link do ...
- osg linux 环境配置,Linux环境下jdk1.8的下载与安装
Linux环境下jdk1.8的下载与安装 1.下载 Oracle官网下载相应的版本,官网地址:https://www.oracle.com/java/technologies/javase/javas ...
- linux闲话FHS标准下linux目录结构
2019独角兽企业重金招聘Python工程师标准>>> 1.闲话 2011年10月24日收到了秒针的OfferLetter并决定加入之后,就开始认真学习linux.坦 ...
最新文章
- MAC使用终端DISKUTIL命令给U盘分区(解决window优盘只有200M)
- ERROR: No query specified(Mysql数据库报错)
- r语言 林元震_科学网—R语言简介 - 林元震的博文
- 【引用】jQuery 选择器
- tomcat6的项目能直接在tomcat7上用吗_极尽人性化的设计: 能“隐形”的笔记本电脑支架...
- 年薪30W的软件测试“老司机”工作经验
- ​最高要价 8888元,小米 11 邀请函现身闲鱼;荣耀与微软签署全球 PC 合作协议;Xfce 4.16 发布|极客头条...
- network of emergency contacts---BFS
- Hypermesh-优化案例学习笔记-cclip
- Servlet 运行工作原理详解
- 网盘共享文件有病毒吗?
- Camera+收入超500万美金,VPlayer能否击败其神话?
- 4.4-软件开发中,“UI设计图”的作用与绘制方法说明
- iOS开发之Crash分析,以及收集
- 键盘上每个键作用!!! (史上最全的)
- 企业员工信息管理系统(C语言编程)
- JUnit version 3.8 or later expected
- wlan从入门到精通第四期WLAN常用概念
- 【创建petstore数据库与表】
- 软件架构设计---软件架构概述
热门文章
- Java 输出指定目录下的所有文件
- MySql数据库常用命令宝典
- ios android 字体颜色,iOS-修改导航栏文字字体和颜色
- Python 小白从零开始 PyQt5 项目实战(7)折叠侧边栏的实现
- 计算机电路基础答案,计算机电路基础模拟试卷答案(B)
- opencv glob 内存溢出异常
- mysql添加用户权限报1064 - You have an error in your SQL syntax问题解决
- Python类的构造方法__init__(self)和析构函数__del__详解
- print的小白用法
- meta http-equiv=X-UA-Compatible content=IE=edge,chrome=1 /