关于linux下汇编语言的问题

欢迎加入我们,一同切磋技术。 &
用户名: &&&
密 码: &
共有 3596 人关注过本帖
标题:linux下Intel汇编使用pushl和movq指令的问题
来 自:向日葵幼儿园
等 级:黑侠
帖 子:306
专家分:586
结帖率:88.89%
&&问题点数:0&&回复次数:1&&&
linux下Intel汇编使用pushl和movq指令的问题
这是我的操作平台:
$ uname -a
Linux ------&&2.6.32-431.11.2.el6.x86_64 #1 SMP Tue Mar 25 19:59:55 UTC
x86_64 x86_64 GNU/Linux
一、movq指令加载内存中的数据到mmx寄存器后,在gdb中使用print命令查看mmx寄存器显示为void
汇编程序:
程序代码:.section .data
&&& .int <font color=#, -<font color=#
&&& .byte <font color=#x10, <font color=#x05, <font color=#xff, <font color=#x32, <font color=#x47, <font color=#xe5, <font color=#x23, <font color=#x12
&&& .quad <font color=#456
.section .text
.globl _start
&&& movq intv, %mm0
&&& movq bytev, %mm1
&&& movq quadv, %mm2
&&& movl $<font color=#, %eax
&&& movl $<font color=#, %ebx
&&& int $<font color=#x80
编译链接:
$ as -gstabs -o mmx.o mmx.s
$ ld -o mmx mmx.o
(gdb)print $mm0
(gdb)print $mm1
(gdb)print $mm2
为什么显示的是void而不是加载进去的值???
二、使用pushl指令出错
程序代码:.section .data
&&& .int <font color=#, <font color=#, <font color=#, <font color=#, <font color=#, <font color=#, <font color=#, <font color=#, <font color=#, <font color=#, <font color=#
&&& .asciz &The value is %d\n&
.section .text
.globl _start
&&& movl $<font color=#, %edi
&&& movl value(, %edi, <font color=#), %eax
&&& pushl %eax
&&& pushl $output
&&& call printf
&&& addl $<font color=#, %esp
&&& inc %edi
&&& cmpl $<font color=#, %edi
&&& jne loop
&&& movl $<font color=#, %ebx
&&& movl $<font color=#, %eax
&&& int $<font color=#x80
编译出错:
$ as -gstabs -o loop.o loop.s
loop.s: Assembler messages:
loop.s:13: Error: suffix or operands invalid for `push'
loop.s:14: Error: suffix or operands invalid for `push'
网上查说加--32参数:
$ as -gstabs -o loop.o loop.s
试了下,编译通过了。
链接出错:
$ ld -o loop loop.o
loop.o: could not read symbols: File in wrong format
$ file loop.o
loop.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
请问造成上述2个问题的原因什么?该如何解
[ 本帖最后由 锋了 于
22:17 编辑 ]
搜索更多相关主题的帖子:
来 自:向日葵幼儿园
等 级:黑侠
帖 子:306
专家分:586
好把,我来回答第二个问题,只要在代码开头加上.code32就可以了,因为我的是64位机子,但写的是32的代码。
第一个问题还不懂
版权所有,并保留所有权利。
Powered by , Processed in 0.052508 second(s), 7 queries.
Copyright&, BCCN.NET, All Rights Reserved博客访问: 163765
博文数量: 34
博客积分: 2010
博客等级: 大尉
技术积分: 390
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX
在linux内核的源代码中,以汇编语言编写的程序或程序段,有两种不同的形式。
  第一种事完全的汇编代码,这样的代码采用.s作为文件的后缀。事实上,尽管是完全的汇编代码,现代的汇编工具也吸收了C语言的长处,也在汇编之前加上
了一趟预处理,而预处理之前的文件则以.s为后缀。此类(.s)文件也和C程序一样,可以使用#include、#ifdef等等成分,而数据结构也一样
可以在.h的文件中加以定义。
  第二种是嵌在C程序中的汇编语言片断。虽然在ANSI的C语言标准中并没有关于汇编片段的规定,事实上各种实际使用的C编译中都作了这方面的扩充,而GNU的C编译gcc也在这方面作了很强的扩充。
  在DOS/windows领域中,386汇编语言都采用Intel定义的语句格式。可是,在Unix领域中,采用的却是由AT&T定义的格式。
  AT&T的汇编与Intel的汇编主要有以下的区别:
在Intel格式中大多使用大写字母,而在AT&T格式中都使用小写字母。
在AT&T格式中,寄存器名要加上“%”作为前缀,而在Intel格式中不带前缀。
在AT&T的386汇编语言中,指令的源操作数的顺序与在Intel的386汇编语言中正好相反。
在AT&T格式中,访问指令的操作数的宽度有操作码名称的最后一个字母(操作码的后缀决定)。用作操作码后缀的字母有b(8位)。
w(16位)和1(32位)。而在Intel格式中,则是在表示内存单元的操作数前面加上“BYTE PTR”“WORD PTR”,“DWORD
PTR”来表示。
在AT$T格式中,直接操作数要加上“$”作为前缀,而在Intel格式中则不带前缀。
在AT$T格式中,绝对转移和调用指令jump/call的操作数要加上“*”作为前缀,而在intel格式则不带。
远程的转移指令和子程序调用指令的操作码名称,在AT$T格式中为“ljump”和“lcall”,而在intel格式中,则为“JMP FAR”和“CALL FAR”当转移和调用的目标为直接操作数时,两种不同的表示如下:
 CALL FAR SECTION:OFFSET(Intel 格式)
 JMP FAR SECTION:OFFSET(Intel 格式)
 lcall $section,$offset (AT$T格式)
 lcall $secton,$offset (AT$T格式). 与之相应的远程返回指令,则为:
 RET FAR STACK_ADJUST (Intel 格式)
 Lret $stack_adjust (AT$T 格式)
间接寻址的一般格式,两者的区别如下:
 SECTION :[BASE+INDEX*SCALE+DISP](Intel 格式)
 Section: disp(base,index,scale)(AT$T 格式)
 当需要在C语言的程序中嵌入一段汇编语言程序时,可以使用gcc提供的“asm”语句功能。
  一般而言,往C代码中插入汇编语言的代码片要比“纯粹”的汇编语言代码复杂的多,因为这里有个怎样分配使用寄存器,怎样与C代码中的变量结合的问题。
为了这个目的,必须对所用的汇编语言作更多的扩充,增加对汇编工具的指导作用。其结果是其语法实际上变成了既不同于汇编语言,也不同于C语言的某种中间语
  插入C代码的一个汇编语言代码片段可以分为四个部分,以“:”号加以分隔,其一般形式为:
指令部: 输出部:输入部:损坏部
  第一部分就是汇编代码本身,其格式和在汇编语言中使用基本相同。这一部分称为“指令部”,是必须有的,而其他部分可视具体情况而省略。
  当将汇编语言代码片段嵌入到C代码中时,操作数与C代码中的变量如何结合显然是个问题。Gcc采用的策略是:程序员提供具体的指令,而对寄存器的使用则一般只提供一个“样板”和一些约束条件,而把到底如何与变量结合的问题留给了gcc和gas处理。
  在指令部中,数字加上前缀%,如%0、%1等等,表示需要使用的寄存器的样板操作数。可以使用的此类操作数的总数取决于具体CPU中通用寄存器的数
量。这样,指令部中用到了几个不同的这种操作数,就说明有几个变量需要与寄存器结合,由gcc和gas在编译和汇编时根据后面的约束条件自行变通处理。由
于这些样板操作数也使用“%”前缀,在涉及到具体的寄存器时就要在寄存器名前面加上两个“%”符,以免混淆。
  紧接在指令部后面的是“输出部”,用以规定对输出变量如何结合的约束条件。每个这样的条件称为一个“约束”。必要是输出部可以有多个约束,互相以逗号
分隔。每个输出约束以“=”号开始,然后是一个字母表示对操作数类型的说明,然后是关于变量结合的约束。凡是与输出部中说明的操作数相结合的寄存器或操作
数本身,在执行嵌入的汇编代码后均不保留执行之前的内容,这就给gcc提供了调度这些寄存器的依据。
  输出部后面是“输入部”。输入约束的格式和输出约束相似,但不带“=”号。如果一个输入约束要求使用寄存器,则在预处理时gcc会为之分配一个寄存
器,并自动插入必要的指将操作数即变量的值装入该寄存器。与输入部中说明的操作数结合的寄存器或操作数本身,在执行嵌入汇编代码后也不保留执行之前的内
  在有些操作中,除用于输入数据操作和输出数的寄存器以外,还要将若干个寄存器用于计算或操作的中间结果。这样,这些寄存器原有的内容就损坏了,所以要在损坏部队操作的副作用加以说明,让gcc采取相应的措施。
  操作数的编号从输出部的第一个约束(序号为0)开始,顺序数下来,每个约束记数一次。在指令部中引用这些操作或分配用于这些操作数的寄存器时,就在序
号前面加上一个“%”号。在指令部中引用一个操作数时总是把它当作一个32位的“长字”,但是对其实施的操作,则根据需要也可以是字节操作或是字操作。对
操作数进行的字节操作时也允许明确指出是对哪一个字节的操作,此时在%与序号之间插入一个“b”表示最低字节,插入一个“h”表示次低字节。
  表示约束调节的字母有很多:
“m”“v”“o” 表示内存单元
“r” 表示任何寄存器
“q” 表示寄存器eax,ebx,ecx,edx之一
“i”和“h” 表示直接操作数
“E”和“F” 表示浮点数
“g”表示任意
“a”,“b”,“c”,“d” 分别表示寄存器eax,ebx,ecx,edx
“S”和“D” 分别表示寄存器esi,edi
表示常数(0至31)
  此外,如果一个操作数要求使用与前某个约束中所要求的是同一个寄存器,那就把与那个约束相对应的操作数标号放在约束条件中。在损坏部常常会以
“memory”为约束条件,表示操作完成后内存中的内容已有改变,如果原来某个寄存器(也许在本次操作汇总并未使用到)的内容来自内存,则现在科能已经
  还要注意,当输出部为空,即没有输出约束时,如果有输入约束存在,则必须保留分隔标记“:”号。备注:(举例)一 基本语法
语法上主要有以下几个不同.
★ 寄存器命名原则
AT&T: %eax Intel: eax
★源/目的操作数顺序
AT&T: movl %eax,%ebx Intel: mov ebx,eax
★常数/立即数的格式
AT&T: movl $_value,%ebx Intel: mov eax,_value
把_value的地址放入eax寄存器
AT&T: movl $0xd00d,%ebx Intel: mov ebx,0xd00d
★ 操作数长度标识
AT&T: movw %ax,%bx Intel: mov bx,ax
★寻址方式
AT&T: immed32(basepointer,indexpointer,indexscale)
Intel: [basepointer + indexpointer*indexscale + imm32)
linux工作于保护模式下,用的是32位线性地址,所以在计算地址时不用考虑segment:offset的问题.上式中的地址应为:
imm32 + basepointer + indexpointer*indexscale
下面是一些例子:
★直接寻址
AT&T: _booga ; _booga是一个全局的C变量
注意加上$是表示地址引用,不加是表示值引用.
注:对于局部变量,可以通过堆栈指针引用.
Intel: [_booga]
★寄存器间接寻址
AT&T: (%eax)
Intel: [eax]
★变址寻址
AT&T: _variable(%eax)
Intel: [eax + _variable]
AT&T: _array(,%eax,4)
Intel: [eax*4 + _array]
AT&T: _array(%ebx,%eax,icon_cool.gif
Intel: [ebx + eax*8 + _array]
二 基本的行内汇编
·基本的行内汇编很简单,一般是按照下面的格式:
asm(&statements&);
例如:asm(&nop&); asm(&cli&);
·asm 和 __asm__是完全一样的.
·如果有多行汇编,则每一行都要加上 &
asm( &pushl %eax
&movl $0,%eax
&popl %eax&);
实际上gcc在处理汇编时,是要把asm(...)的内容&打印&到汇编文件中,所以格式控制字符是必要的.
asm(&movl %eax,%ebx&);
asm(&xorl %ebx,%edx&);
asm(&movl $0,_booga);
在上面的例子中,由于我们在行内汇编中改变了edx和ebx的值,但是由于gcc的特殊的处理方法,即先形成汇编文件,再交给GAS去汇编,所以GAS并
不知道我们已经改变了edx和ebx的值,如果程序的上下文需要edx或ebx作暂存,这样就会引起严重的后果.对于变量_booga也存在一样的问题.
为了解决这个问题,就要用到扩展的行内汇编语法.
三 扩展的行内汇编
扩展的行内汇编类似于Watcom.
基本的格式是:
asm ( &statements& : output_regs : input_regs : clobbered_regs);
clobbered_regs指的是被改变的寄存器.
下面是一个例子(为方便起见,我使用全局变量):
int count=1;
int value=1;
int buf[10];
void main()
: &c& (count), &a& (value) , &D& (buf[0])
: &%ecx&,&%edi& );
得到的主要汇编代码为:
movl count,%ecx
movl value,%eax
movl buf,%edi
cld,rep,stos就不用多解释了.这几条语句的功能是向buf中写上count个value值.冒号后的语句指明输入,输出和被改变的寄存器.通过冒号以后的语句,编译器就知道你的指令需要和改变哪些寄存器,从而可以优化寄存器的分配.
其中符号&c&(count)指示要把count的值放入ecx寄存器
类似的还有:
I 常数值,(0 - 31)
q,r 动态分配的寄存器
g eax,ebx,ecx,edx或内存变量
A 把eax和edx合成一个64位的寄存器(use long longs)
我们也可以让gcc自己选择合适的寄存器.
如下面的例子:
asm(&leal (%1,%1,4),%0&
: &=r& (x)
: &0& (x) );
这段代码实现5*x的快速乘法.
得到的主要汇编代码为:
movl x,%eax
leal (%eax,%eax,4),%eax
movl %eax,x
几点说明:
1.使用q指示编译器从eax,ebx,ecx,edx分配寄存器.使用r指示编译器从eax,ebx,ecx,edx,esi,edi分配寄存器.
2.我们不必把编译器分配的寄存器放入改变的寄存器列表,因为寄存器已经记住了它们.
3.&=&是标示输出寄存器,必须这样用.
4.数字%n的用法:
数字表示的寄存器是按照出现和从左到右的顺序映射到用&r&或&q&请求的寄存器.如果我们要重用&r&或&q&请求的寄存器的话,就可以使用它们.
5.如果强制使用固定的寄存器的话,如不用%1,而用ebx,则asm(&leal (%%ebx,%%ebx,4),%0&
: &=r& (x)
: &0& (x) );
注意要使用两个%,因为一个%的语法已经被%n用掉了.
下面可以来解释letter 的问题:
1、变量加下划线和双下划线有什么特殊含义吗?
加下划线是指全局变量,但我的gcc中加不加都无所谓.
2、以上定义用如下调用时展开会是什么意思?
#define _syscall1(type,name,type1,arg1)
type name(type1 arg1)
/* __res应该是一个全局变量 */
__asm__ volatile (&int $0x80&
/* volatile 的意思是不允许优化,使编译器严格按照你的汇编代码汇编*/
: &=a& (__res)
/* 产生代码 movl %eax, __res */
: &0& (__NR_##name),&b& ((long)(arg1)));
/* 如果我没记错的话,这里##指的是两次宏展开.
  即用实际的系统调用名字代替&name&,然后再把__NR_...展开.
  接着把展开的常数放入eax,把arg1放入ebx */
if (__res &= 0)
return (type) __
errno = -__
return -1;
阅读(2819) | 评论(1) | 转发(1) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。linux汇编 常见问题 (zz) - CSDN博客
linux汇编 常见问题 (zz)
&http://firstdot./
1.gcc嵌入汇编(1). 在gcc嵌入汇编中输入输出使用相同的寄存器?
static void * __memcpy(void * to, const void * from, size_t n){&int d0,d1,d2;&__asm__ __volatile__(&&&movsl/n/t&&&&testb $2,%b4/n/t&&&&je 1f/n/t&&&&movsw/n&&&&1:/ttestb $1,%b4/n/t&&&&je 2f/n/t&&&&movsb/n&&&&2:&&&:&=&c& (d0), &=&D& (d1), &=&S& (d2)&&:&0& (n/4), &q& (n), &1& ((long) to), &2& ((long) from)&&:&memory&);&return (to);}
操作数0,1,2和3,5,6使用相同的寄存器的理解:a. 3,5,6在输入过程中将值n/4,to和from的地址读入ecx,edi,esi寄存器中;b. 0,1,2在输出过程中将ecx,edi,esi寄存器中的值存入d0,d1,d2内存变量中。c. 注意在上面的语句中也有&&&限定符,但输入和输出仍使用相同的寄存器,如操作数0和3都使用寄存器ecx,这是因为&0&限定的结果,如果
把&0& (n/4)换成&c& (n/4),则因为&=&c&的限定而使得编译时报错。
(2). 关于gcc嵌入式汇编中&&&限定符的作用?&&&限定符用于输出操作数,使其唯一的使用某寄存器
int bar,__asm__ __volatile__(&&call func /n/t&&&mov ebx,%1&&:&=a& (foo)&:&r& (bar));
在gcc编译时默认会让bar也使用eax寄存器,如果把&=a&改为&=&a&,那么foo将唯一使用eax,而让bar使用其它的寄存器。
(3). _start和main的关系?main是gcc看到的程序入口点,而ld和as所看到的程序入口点其实是_start。libc库中的_start会调用main函数。a. 编译带_start的汇编程序时的步骤:as -o a.o a.s,ld -o a a.o; gcc -g -c a.s,ld -o a a.o。(使用gcc编译可以增加调试选项-g,这
时不能直接用gcc -o a a.s编译的原因是gcc会默认在程序中查找main函数,并且会将libc中的_start加入进来。如果直接用gcc -o a a.s编译
,则会报两个错误&重复的_start&和&没找到main&)b. 编译带main的汇编程序或C程序时的步骤:gcc -o a a.s;gcc -o a a.c。
(4).section和.previous将这两个.section和.previous中间的代码汇编到各自定义的段中,然后跳回去,将这之后的的代码汇编到上一个section中(一般是.text段),
也就是自定义段之前的段。.section和.previous必须配套使用。
2. AT&T汇编(1).data,.section等都是伪操作,不能直接翻译成机器码,只有相应的assembler才能识别(2).section将程序分成几个片断,如.data,.text,.bss(3).globl 函数名表示该函数被export,并可以被其它文件中的函数调用(4).bss可以用来申请一块空间,但不需要对其进行初始化(5)使用内核定义函数如open,read等可以通过int $80中断来完成(6)MOVL $FOO,%EAX是把FOO在内存中的地址放到EAX中,而MOVL FOO,%EAX是把FOO这个变量的内容放入EAX (7).include &文件名&,将其它文件包含进来(8)如何在汇编中表示结构?如c语言中的如下结构:struct para{&char Firstname[40];&char Lastname[40];&char Address[240];&long A//4 bytes}在汇编中可以表示成:.section datarecord1:.ascii &Fredrick/0&.rept 31 #Padding to 40 bytes.byte 0.endr.ascii &Bartlett/0&.rept 31 #Padding to 40 bytes.byte 0.endr.ascii &4242 S Prairie/nTulsa, OK 55555/0&.rept 209 #Padding to 240 bytes.byte 0.endr.long 45其中.rept n和.endr表示重复两者之间的序列n次,可用于填充数据(9)当汇编程序由多个文件构成时,可以采用以下方式编译与连接:as write-records.s -o write-records.o (gcc -g -c write-records.s)as write-record.s -o write-record.o (gcc -g -c write-record.s)ld write-record.o write-records.o -o write-records(10)如何在汇编语言中使用动态库中的函数?#helloworld-lib.s.section .datahelloworld:.ascii &hello world/n/0&.section .text.globl _start_start:pushl $helloworldcall printfpushl $0call exit
as helloworld-lib.s -o helloworld-lib.old -dynamic-linker /lib/ld-linux.so.2 -o helloworld-lib helloworld-lib.o -lc产生动态库:ld -shared write-record.o read-record.o -o librecord.so(11)使用汇编文件生成动态库as write-record.s -o write-record.oas read-record.s -o read-record.old -shared write-record.o read-record.o -o librecord.soas write-records.s -o write-records.old -L . -dynamic-linker /lib/ld-linux.so.2 -o write-records -lrecord write-records.o记得运行write-records时还需要将动态库路径加到/etc/ld.so.conf中,并运行ldconfig(12)编译汇编文件时如何产生调试符号as --gstabs a.s -0 a.o 或者gcc -g -c a.s
附录:(1)函数调用时栈的情况#Parameter #N &--- N*4+4(%ebp)#...#Parameter 2 &--- 12(%ebp)#Parameter 1 &--- 8(%ebp)#Return Address &--- 4(%ebp)#Old %ebp &--- (%ebp)#Local Variable 1 &--- -4(%ebp)#Local Variable 2 &--- -8(%ebp) and (%esp)
(2)例子&.include &external_func.s&
&.section .datadata_array:&&&& #定义long型数组&.long 3,67,34,0&&&&&&&& data_strings:&&& #定义字符串&.ascii &Hello there/0&data_long:&#定义long型变量&.long 5
&.section .bss&.lcomm my_buffer, 500&& #申请一块500字节的内存
&.section .text&.equ LINUX_SYSCALL, 0x80 #定义符号LINUX_SYSCALL的值为0x80&.globl _start_start:&pushl %edx&movl data_long,%edx&&&& #将data_long变量的值放入edx寄存器&movl $data_long,%edx&&& #将data_long的地址放入edx寄存器&popl %edx
&pushl $3&&&&& #push second argument&pushl $2&&&&& #push first argument&call power&&& #call the function&addl $8, %esp #move the stack pointer back&pushl %eax&&& #save the first answer before,calling the next function
&movl $1, %eax #exit (%ebx is returned)&int $LINUX_SYSCALL&&&&
&.type power, @function #定义函数powerpower:&pushl %ebp&&&&&&&& #save old base pointer&movl %esp, %ebp&&& #make stack pointer the base pointer&subl $4, %esp&&&&& #get room for our local storage&movl 8(%ebp), %eax #put first argument in %eax&movl 12(%ebp), %ebx #put second argument in %ebx&imull %ebx,%eax&movl %ebp, %esp&&& #restore the stack pointer&popl %ebp&&&&&&&&& #restore the base pointer&ret
本文已收录于以下专栏:
相关文章推荐
http://www.chinavideo.org/viewthread.php?tid=989&extra=page=1
[H.264_FAQ集锦]
本贴是大家在...
附: 8086汇编,俄罗斯方块完整代码:
/Dulun/Assembly1.低级错误忘记设置data段mov ax,data
mov ds, ax2....
http://blog.csdn.net/zcf/article/details/8546772
***** 目录 *****
第一部分:安装显卡驱动
(1-1)硬件配置要求...
今晚有空把最近运维中遇到的一些问题及解决方法总结下,写的比较匆忙,可能有些问题和错误,请各位看官指正。
————————————————————————————————————
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)Linux汇编语言开发指南 pdf格式
为鼓励上传资源,我们采用积分下载方式,希望您能发布更多更好的资源互相分享
1.上传软件或电子书,源码,资料等,审核后即获2积分;如发布时设了下载需积分,其他用户下载后你将获得相应积分
2.当您首次注册时,可以获送10个下载积分,供您下载资源和熟悉网站下载的使用
3.发现资源有误或其他问题,通过举报按钮反馈后我们将奖励积分
4.您可以在论坛通过发帖等方式获取
5.参加本站可以在有效期内不限次数下载
6.您也(1元=10积分)或
7.我们会不定期举办各种活动,参加活动可以获取积分,请关注下载频道首页公告。
您可能遇到这些“伪问题”:
1.资料无法解压:
请确保所有分卷均下载完毕,如果有未知后缀文件,请搜索相应解压软件;
2.chm文件无内容:
您的电脑锁定了这一文件,请右击文件属性,点击右下方“解除锁定”,关闭文件后再打开;
3.下载不下来:
请尝试重新下载(重新下载不扣积分);
4.杀毒软件报毒:
黑客安全及破解类软件容易报毒,但可正常使用,如担心安全请谨慎使用。
汇编语言开发指南
汇编语言的优点是速度快,可以直接对硬件进行操作,这对诸如图形处理等关键应
用是非常重要的。Linux 是一个用 C 语言开发的操作,这使得很多程序员开始
忘记在 Linux 中还可以直接使用汇编这一底层语言来优化程序的性能。本文为那些
在 Linux 平台上编写汇编代码的程序员提供指南,介绍 Linux 汇编语言的语法格式
和开发工具,并辅以具体的例子讲述如何开发实用的 Linux 汇序。&
作为最基本的编程语言之一,汇编语言虽然应用的范围不算很广,但重要性却勿庸
置疑,因为它能够完成许多其它语言所无法完成的功能。就拿 Linux 内核来讲,虽
然绝大部分代码是用 C 语言编写的,但仍然不可避免地在某些关键地方使用了汇
编代码,其中主要是在 Linux 的启动部分。由于这部分代码与硬件的关系非常密
切,即使是 C 语言也会有些力不从心,而汇编语言则能够很好扬长避短,最大限
度地发挥硬件的性能。&
大多数情况下 Linux 程序员不需要使用汇编语言,因为即便是硬件驱动这样的底层
程序在 Linux 操作系统中也可以用完全用 C 语言来实现,再加上 GCC 这一优秀的
编译器目前已经能够对最终生成的代码进行很好的优化,的确有足够的理由让我们
可以暂时将汇编语言抛在一边了。但实现情况是 Linux 程序员有时还是需要使用汇
编,或者不得不使用汇编,理由很简单:精简、高效和 libc 无关性。假设要移植&
Linux 到某一特定的嵌入式硬件环境下,首先必然面临如何减少系统大小、提高执
行效率等问题,此时或许只有汇编语言能帮上忙了。&
汇编语言直接同计算机的底层软件甚至硬件进行交互,它具有如下一些优点:&
& &能够直接访问与硬件相关的存储器或 I/O 端口; &
& &能够不受编译器的限制,对生成的二进制代码进行完全的控制; &
& &能够对关键代码进行更准确的控制,避免因线程共同访问或者硬件设备共享
引起的死锁; &
& &能够根据特定的应用对代码做最佳的优化,提高运行速度; &
& &能够最大限度地发挥硬件的功能。
您对本软件有什么意见或着疑问吗?请到您的关注和建议是我们前行的参考和动力
下载地址:
您正在下载:Linux汇编语言开发指南 pdf格式
热门最新推荐
您的浏览器不支持嵌入式框架,或者当前配置为不显示嵌入式框架。
文章下载读书

我要回帖

更多关于 linux下汇编语言 的文章

 

随机推荐