AT&T x86 asm 语法! for linux kernel

Zgh啊慧

Zgh啊慧

2016-01-29 18:20

AT&T x86 asm 语法! for linux kernel,AT&T x86 asm 语法! for linux kernel
创建时间:2001-04-09文章属性:翻译文章提交:e4gle (e4gle_at_hackermail.com)AT&T x86 asm 语法译:el8,alert7 from m4in security teams(www.m4in.org)DJGPP 使用AT&T格式的汇编语法。和一般的intel格式的语法有点不同。主要不同点如下:AT&T 语法颠倒了源和目的操作数的位置, 目的操作数在源操作数之后。寄存器操作数要有个%的前缀, 立即数操作数要有个$符号的前缀。 存储器操作数的大小取决于操作码的最后一个字符。 它们是b (8-bit), w (16-bit), 和 l (32-bit). 这里有一些例子。 左边部分是intel指令格式,右边是at&t格式。 movw %bx, %ax // mov ax, bx xorl %eax, %eax // xor eax, eax movw , %ax // mov ax,1 movb X, %ah // mov ah, byte ptr X movw X, %ax // mov ax, word ptr X movl X, %eax // mov eax, X大部分操作指令,at%t和intel都是差不多的,除了这些: movsSD // movsx movzSD // movzS和D分辨代表源和目的操作数后缀。 movswl %ax, %ecx // movsx ecx, ax cbtw // cbw cwtl // cwde cwtd // cwd cltd // cdq lcall $S,$O // call far S:O ljmp $S,$O // jump far S:O lret $V // ret far V操作嘛前缀不能与他们作用的指令写在同一行。 例如, rep 和stosd应该是两个相互独立的指令, 存储器的情况也有一点不同。通常intel格式的如下: section:[base + index*scale + disp] 被写成: section:disp(base, index, scale) 这里有些例子: movl 4(%ebp), %eax // mov eax, [ebp+4]) addl (%eax,%eax,4), %ecx // add ecx, [eax + eax*4]) movb , %fs:(%eax) // mov fs:eax, 4) movl _array(,%eax,4), %eax // mov eax, [4*eax + array]) movw _array(%ebx,%eax,4), %cx // mov cx, [ebx + 4*eax + array])Jump 指令通常是个短跳转。 可是, 下面这些指令都是只能在一个字节的范围内跳转: jcxz, jecxz, loop, loopz, loope, loopnz 和loopne。象在线文档所说的那样,一个jcxz foo可以扩展成以下工作: jcxz cx_zero jmp cx_nonzerocx_zero: jmp foocx_nonzero:文档也注意到了mul和imul指令。 扩展的乘法指令只用一个操作数,例如, imul $ebx, $ebx将不会把结果放入edx:eax。使用imul %ebx中的单操作数来获得扩展结果。 --------------------------------------------------------------------------------Inline Asm我将首先开始inline asm, 因为似乎关于这方面的疑问非常多。这是最基本的语法了, 就象在线帮助信息中描述的:__asm__(asm statements : outputs : inputs : registers-modified); 这四个字段的含义是: asm statements - AT&T 的结构, 每新行都是分开的。 outputs - 修饰符一定要用引号引起来, 用逗号分隔 inputs - 修饰符一定要用引号引起来, 用逗号分隔 registers-modified - 名字用逗号分隔一个小小的例子: __asm__(" pushl %eaxn movl , %eaxn popl %eax" );假如你不用到特别的输入输出变量或者修改任何寄存器的值,一般来说是不会使用到其他的三个字段的, 让我们来分析一下输入变量。 int i = 0; __asm__(" pushl %%eaxn movl %0, %%eaxn addl , %%eaxn movl %%eax, %0n popl %%eax" : : "g" (i) ); // increment i不要为上面的代码所困扰! 我将尽力来解释它。我们想让输入变量i加1,我们没有任何输出变量, 也没有改变寄存器值(我们保存了eax值)。 因此,第二个和最后一个字段是空的。 因为指定了输入字段, 我们仍需要保留一个空的输出字段, 但是没有最后一个字段, 因为它没被使用。在两个空冒号之间留下一个新行或者至少一个空格。下面让我们来看看输入字段。 附加描述符可以修正指令来让你给定的编译器来正确处理这些变量。他们一般被附上双引号。 那么这个"g"是用来做什么的呢? 只要是合法的汇编指令,"g"就让编译器决定该在哪里加载i的值。一般来说,你的大部分输入变量都可以被赋予"g", 让编译器决定如何去加载它们 (gcc甚至可以优化它们!)。 其他描述符使用"r" (加载到任何可用的寄存器去), "a" (ax/eax), "b" (bx/ebx), "c" (cx/ecx), "d" (dx/edx), "D" (di/edi), "S" (si/esi), 等等。 我们将要提到一个在asm代码里面的如%0的输入变量。如果我们有两个输入, 他们会一个是%0一个是%1, 在输入段里按顺序排列 (如下一个例子)。假如N个输入变量且没有输出变量, 从%0 到%N-1将和输入字段里的变量相对应, 按顺序排列。 如果任何的输入, 输出, 寄存器修改字段被使用, 汇编代码里的寄存器名必须用两个%来代替一个%。对应于第一个没有使用最后三个字段的例子。让我们看看两个输入变量且引入了"volatile"的例子: int i=0, j=1; __asm__ __volatile__(" pushl %%eaxn movl %0, %%eaxn addl %1, %%eaxn movl %%eax, %0n popl %%eax" : : "g" (i), "g" (j) ); // increment i by jOkay, 现在我们已经有了两个输入变量了。没问题了, 我们只需要记住%0对应第一个输入变量(在
展开更多 50%)
分享

猜你喜欢

AT&T x86 asm 语法! for linux kernel

Linux Linux命令 Linux安装 Linux编程 Linux桌面 Linux软件 Linux内核 Linux管理
AT&T x86 asm 语法! for linux kernel

x86内联汇编

编程语言 网络编程
x86内联汇编

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

手把手教你安装Android x86

电脑入门
手把手教你安装Android x86

Linux中有没有支援 Solairs x86 的档案系统?有的话要如何mount?

Linux Linux命令 Linux安装 Linux编程 Linux桌面 Linux软件 Linux内核 Linux管理
Linux中有没有支援 Solairs x86 的档案系统?有的话要如何mount?

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

《AT&T 采用新标志》

平面设计 标志设计 UI设计 VI设计
《AT&T 采用新标志》

《AT&T 创意广告设计》

平面设计 海报设计 海报设计素材 广告设计 平面设计素材
《AT&T 创意广告设计》

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

提高系统内存效能的五大技巧

提高系统内存效能的五大技巧

samba服务器的文件共享配置

samba服务器的文件共享配置
下拉加载更多内容 ↓