AT&T x86 asm 语法! for linux kernel

2016-01-29 18:20 0 1 收藏

AT&T x86 asm 语法! for linux kernel,AT&T x86 asm 语法! for linux kernel

【 tulaoshi.com - Linux 】

创建时间: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对应第一个输入变量(在

来源:https://www.tulaoshi.com/n/20160129/1505387.html

延伸阅读
1.定义变量时可以直接赋值 DECLARE @Id int = 5 2.Insert 语句可以一次插入多行数据 INSERT INTO StateList VALUES(@Id, 'WA'), (@Id + 1, 'FL'), (@Id + 2, 'NY') 3.支持+=操作符 SET StateId += 1 完整示例如下: 代码如下: CREATE TABLE StateList(StateId int, StateName char(2)) GO -- Declare variable and assign a value in...
  有时候在X里由于程序出错鼠标键盘都不起作用,这时候不用着急,因为在Linux下几乎不会像在Win95里那样恶性死机,你只须键入Ctrl+Alt+BackSpace键就可以回到字符界面下了。  
手形艺术AT&T广告设计欣赏[2P] 图片1 图片2 图片3
标签: 服务器
Linux系统下glibc导致kernel panic的问题修复方法   Linux操作系统是基于UNIX操作系统发展而来的一种克隆系统,以后借助于Internet网络,并通过全世界各地计算机爱好者的共同努力,已成为今天世界上使用最多的一种UNIX 类操作系统,并且使用人数还在迅猛增长。虽然在用户使用中很受欢迎,但是也存在一些问题,比如:因glibc导致kerne...
标签: 服务器
Linux Kernel 4.5在3月15日发布最终版   今天Linus Torvalds和辛苦工作的内核团队非常自豪的宣布了Linux Kernel 4.5版本,并已经开放下载。自2016年1月25日首个候选版本发布,经历了长达两个多月的不懈更新,在3月6日发布最后一个候选版本之后,Linux Kernel 4.5终于在今天获得了最终版本。 Linux Kernel 4.5的突出特性包括...

经验教程

720

收藏

94
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部