⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 preparing-asm_4.htm

📁 编写自己的操作系统
💻 HTM
📖 第 1 页 / 共 5 页
字号:
  <LI><FONT face="Times New Roman TUR">进行总线加锁(lock);</FONT> 
  <LI><FONT face="Times New Roman TUR">指定地址和操作的大小(data16,addr16);</FONT></LI></UL>
<P><FONT 
face="Times New Roman TUR">在AT&amp;T汇编语法中,操作码前缀通常被单独放在一行,后面不跟任何操作数。例如,对于重复scas指令,其写法为:</FONT></P>
<P><FONT 
face="Times New Roman TUR">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
repne<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
scas</FONT></P>
<P><FONT face="Times New Roman TUR">上述操作码前缀的意义和用法如下:</FONT></P>
<UL>
  <LI><FONT 
  face="Times New Roman TUR">指定被操作的段前缀为cs,ds,ss,es,fs,和gs。在AT&amp;T语法中,只需要按照section:memory-operand的格式就指定了相应的段前缀。比如:lcall&nbsp;%cs:realmode_swtch</FONT> 

  <LI><FONT 
  face="Times New Roman TUR">操作数/地址大小前缀是“data16”和"addr16",它们被用来在32-bit操作数/地址代码中指定16-bit的操作数/地址。</FONT> 

  <LI><FONT 
  face="Times New Roman TUR">总线加锁前缀“lock”,它是为了在多处理器环境中,保证在当前指令执行期间禁止一切中断。这个前缀仅仅对ADD, 
  ADC, AND, BTC, BTR, BTS, CMPXCHG,DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, 
  XADD,XCHG指令有效,如果将Lock前缀用在其它指令之前,将会引起异常。</FONT> 
  <LI><FONT 
  face="Times New Roman TUR">字符串重复操作前缀"rep","repe","repne"用来让字符串操作重复“%ecx”次。<BR></FONT></LI></UL>
<P><STRONG><FONT face="Times New Roman TUR">9. 内存引用</FONT></STRONG></P>
<P><FONT face="Times New Roman TUR">Intel语法的间接内存引用的格式为:</FONT></P>
<P><FONT 
face="Times New Roman TUR">section:[base+index*scale+displacement]</FONT></P>
<P><FONT face="Times New Roman TUR">而在AT&amp;T语法中对应的形式为:</FONT></P>
<P><FONT 
face="Times New Roman TUR">section:displacement(base,index,scale)</FONT></P>
<P><FONT face="Times New Roman TUR">其中,base和index是任意的32-bit 
base和index寄存器。scale可以取值1,2,4,8。如果不指定scale值,则默认值为1。section可以指定任意的段寄存器作为段前缀,默认的段寄存器在不同的情况下不一样。如果你在指令中指定了默认的段前缀,则编译器在目标代码中不会产生此段前缀代码。</FONT></P>
<P><FONT face="Times New Roman TUR">下面是一些例子:</FONT></P>
<P><FONT 
face="Times New Roman TUR">-4(%ebp):base=%ebp,displacement=-4,section没有指定,由于base=%ebp,所以默认的section=%ss,index,scale没有指定,则index为0。</FONT></P>
<P><FONT 
face="Times New Roman TUR">foo(,%eax,4):index=%eax,scale=4,displacement=foo。其它域没有指定。这里默认的section=%ds。</FONT></P>
<P><FONT 
face="Times New Roman TUR">foo(,1):这个表达式引用的是指针foo指向的地址所存放的值。注意这个表达式中没有base和index,并且只有一个逗号,这是一种异常语法,但却合法。</FONT></P>
<P><FONT face="Times New Roman TUR">%gs:foo:这个表达式引用的是放置于%gs段里变量foo的值。</FONT></P>
<P><FONT 
face="Times New Roman TUR">如果call和jump操作在操作数前指定前缀“*”,则表示是一个绝对地址调用/跳转,也就是说jmp/call指令指定的是一个绝对地址。如果没有指定"*",则操作数是一个相对地址。</FONT></P>
<P><FONT 
face="Times New Roman TUR">任何指令如果其操作数是一个内存操作,则指令必须指定它的操作尺寸(byte,word,long),也就是说必须带有指令后缀(b,w,l)。</FONT></P>
<P><STRONG><FONT face="Times New Roman TUR">
<HR width="100%" SIZE=2>
</FONT></STRONG>
<P></P>
<P><FONT face="Times New Roman TUR"></FONT></P>
<P><FONT face="Times New Roman TUR"></FONT></P>
<P class=MsoNormal 
style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; tab-stops: list 21.0pt; mso-list: l5 level1 lfo3"><FONT 
face="Times New Roman TUR" size=5><STRONG>0.4.3&nbsp;GCC Inline 
ASM</STRONG></FONT></P>
<P><FONT face=System>GCC支持在C/C++代码中嵌入汇编代码,这些汇编代码被称作GCC Inline 
ASM——GCC内联汇编。这是一个非常有用的功能,有利于我们将一些C/C++语法无法表达的指令直接潜入C/C++代码中,另外也允许我们直接写C/C++代码中使用汇编编写简洁高效的代码。</FONT></P>
<P><FONT size=4><STRONG>1.基本内联汇编</STRONG></FONT></P>
<P><FONT face=System>GCC中基本的内联汇编非常易懂,我们先来看两个简单的例子:</FONT></P>
<P><FONT face=System>__asm__("movl&nbsp;%esp,%eax");&nbsp; // 
看起来很熟悉吧!</FONT></P>
<P><FONT face=System>或者是</FONT></P>
<P><FONT 
face=System>__asm__("<BR>&nbsp;&nbsp;&nbsp;movl&nbsp;$1,%eax&nbsp;&nbsp;// 
SYS_exit<BR>&nbsp;&nbsp;&nbsp;xor&nbsp;%ebx,%ebx<BR>&nbsp;&nbsp;&nbsp;int&nbsp;$0x80<BR>&nbsp;");</FONT></P>
<P><FONT face=System>或</FONT></P>
<P><FONT 
face=System>__asm__(<BR>&nbsp;&nbsp;&nbsp;"movl&nbsp;$1,%eax\r\t"&nbsp;\<BR>&nbsp;&nbsp;&nbsp;"xor&nbsp;%ebx,%ebx\r\t" 
\<BR>&nbsp;&nbsp;&nbsp;"int&nbsp;$0x80" \<BR>&nbsp;&nbsp; );</FONT></P>
<P><FONT face=System>基本内联汇编的格式是</FONT></P>
<P><FONT face=System>__asm__ __volatile__("Instruction List");</FONT></P>
<P><FONT face="Times New Roman TUR"><BR><FONT 
face=System><STRONG>1、__asm__</STRONG></FONT></P></FONT>
<P><FONT face=System>__asm__是GCC关键字asm的宏定义:</FONT></P>
<P><FONT face=System>#define __asm__ asm</FONT></P>
<P><FONT 
face=System>__asm__或asm用来声明一个内联汇编表达式,所以任何一个内联汇编表达式都是以它开头的,是必不可少的。</FONT></P>
<P><STRONG><FONT face=System>2、Instruction List</FONT></STRONG></P>
<P><FONT face=System>Instruction List是汇编指令序列。它可以是空的,比如:__asm__ __volatile__(""); 
或__asm__ ("");都是完全合法的内联汇编表达式,只不过这两条语句没有什么意义。但并非所有Instruction 
List为空的内联汇编表达式都是没有意义的,比如:__asm__ ("":::"memory"); 
就非常有意义,它向GCC声明:“我对内存作了改动”,GCC在编译的时候,会将此因素考虑进去。</FONT></P>
<P><FONT face=System>我们看一看下面这个例子:</FONT></P>
<P><FONT face=System>$ cat example1.c</FONT></P>
<P><FONT face=System>int main(int __argc, char* __argv[])&nbsp; 
<BR>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int* __p = 
(int*)__argc;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*__p) = 
9999;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<EM>//__asm__("":::"memory");</EM>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((*__p) == 
9999)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
return 
5;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 
(*__p);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>}</FONT></P>
<P><FONT 
face=System>在这段代码中,那条内联汇编是被注释掉的。在这条内联汇编之前,内存指针__p所指向的内存被赋值为9999,随即在内联汇编之后,一条if语句判断__p所指向的内存与9999是否相等。很明显,它们是相等的。GCC在优化编译的时候能够很聪明的发现这一点。我们使用下面的命令行对其进行编译:</FONT></P>
<P><FONT face=System>$&nbsp;gcc -O -S example1.c</FONT></P>
<P><FONT 
face=System>选项-O表示优化编译,我们还可以指定优化等级,比如-O2表示优化等级为2;选项-S表示将C/C++源文件编译为汇编文件,文件名和C/C++文件一样,只不过扩展名由.c变为.s。</FONT></P>
<P><FONT face=System>我们来查看一下被放在example1.s中的编译结果,我们这里仅仅列出了使用gcc 2.96在redhat 
7.3上编译后的相关函数部分汇编代码。为了保持清晰性,无关的其它代码未被列出。</FONT></P>
<P><FONT face=System>$ cat example1.s</FONT></P>
<P><FONT 
face=System>main:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl&nbsp;&nbsp; 
%ebp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp; %esp, 
%ebp&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
movl&nbsp;&nbsp;&nbsp; 8(%ebp), %eax&nbsp;&nbsp;&nbsp;&nbsp; # int* __p = 
(int*)__argc<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
movl&nbsp;&nbsp;&nbsp; $9999, (%eax)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # (*__p) = 
9999&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp; 
$5, 
%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
#&nbsp;return 5<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
popl&nbsp;&nbsp;&nbsp; 
%ebp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret</FONT></P>
<P><FONT 
face=System>参照一下C源码和编译出的汇编代码,我们会发现汇编代码中,没有if语句相关的代码,而是在赋值语句(*__p)=9999后直接return 
5;这是因为GCC认为在(*__p)被赋值之后,在if语句之前没有任何改变(*__p)内容的操作,所以那条if语句的判断条件(*__p) == 
9999肯定是为true的,所以GCC就不再生成相关代码,而是直接根据为true的条件生成return 
5的汇编代码(GCC使用eax作为保存返回值的寄存器)。</FONT></P>
<P><FONT face=System>我们现在将example1.c中内联汇编的注释去掉,重新编译,然后看一下相关的编译结果。</FONT></P>
<P><FONT face=System>$&nbsp;gcc -O -S example1.c</FONT></P>
<P><FONT face=System>$ cat example1.s</FONT></P>
<P><FONT 
face=System>main:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl&nbsp;&nbsp; 
%ebp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp; %esp, 
%ebp&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
movl&nbsp;&nbsp;&nbsp; 8(%ebp), %eax&nbsp;&nbsp; # int* __p = 
(int*)__argc<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
movl&nbsp;&nbsp;&nbsp; $9999, (%eax)&nbsp;&nbsp;&nbsp; # (*__p) = 
9999<BR>#APP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
</FONT></P>
<P><FONT 
face=System>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# 
__asm__("":::"memory")<BR>#NO_APP<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
cmpl&nbsp;&nbsp;&nbsp; $9999, (%eax)&nbsp;&nbsp;&nbsp; # (*__p) == 9999 
?<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jne&nbsp;&nbsp;&nbsp;&nbsp; 
.L3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp; # false &nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -