全部博文(130)
分类: 其他平台
2014-05-08 22:26:04
AT&T ASM汇编语法
asm("instruction list":out_put:in_put:clobber/modify);
其中,基于asm带有c/c++表达式的汇编语法中寄存器的使用要%%
asm汇编:mov src,dst
intel汇编:mov dst,src
操作表达式"m"(__in1),它被 GCC 替换之后,
表现为 addl address_of_in1, %% eax,__in1 的地址是什么?编译时才知道。所以我们完全
无法直接在指令中去写出__in1 的地址,这时使用占位符,交给 GCC 在编译时进行替代,
就可以解决这个问题
Clobber and Modify
有时候,你想通知 GCC 当前内联汇编语句可能会对某些寄存器或内存进行修改,希望
GCC 在编译时能够将这一点考虑进去。那么你就可以在 Clobber/Modify 域声明这些寄存
器或内存。
这种情况一般发生在一个寄存器出现在"Instruction List" ,但却不是由 Input/Output
操作表达式所指定的,也不是在一些 Input/Output 操作表达式使用"r","g"约束时由 GCC
为其选择的,同时此寄存器被"Instruction List" 中的指令修改,而这个寄存器只是供当前内
联汇编临时使用的情况。比如:
__asm__("mov %0,%%ebx"::"a"(input):"ebx")
寄存器%ebx 出现在"Instruction List 中" ,并且被 movl 指令修改,但却未被任何
Input/Output 操作表达式指定, 所以你需要在 Clobber/Modify 域指定"bx", 以让 GCC 知
道这一点。
因为你在 Input/Output 操作表达式所指定的寄存器,或当你为一些 Input/Output 操
作表达式使用"r","g"约束, 让 GCC 为你选择一个寄存器时, GCC 对这些寄存器是非常清楚
的—— 它知道这些寄存器是被修改的, 你根本不需要在 Clobber/Modify 域再声明它们。 但
除此之外,GCC 对剩下的寄存器中哪些会被当前的内联汇编修改一无所知。所以如果你真
的在当前内联汇编指令中修改了它们, 那么就最好在 Clobber/Modify 中声明它们, 让 GCC
针对这些寄存器做相应的处理。 否则有可能会造成寄存器的不一致, 从而造成程序执行错误。
如果一个内联汇编语句的 Clobber/Modify 域存在"memory", 那么 GCC 会保证在此内
联汇编之前, 如果某个内存的内容被装入了寄存器, 那么在这个内联汇编之后, 如果需要使
用这个内存处的内容, 就会直接到这个内存处重新读取, 而不是使用被存放在寄存器中的拷
贝。因为这个时候寄存器中的拷贝已经很可能和内存处的内容不一致了。
__asm__("":::"memory");
内存寻址方式
Intel 语法的间接内存引用的格式为:
section:[base+index*scale+displacement]
而在 AT&T 语法中对应的形式为:
section:displacement(base,index,scale)
其中, base 和 index 是任意的 32 -bit base 和 index 寄存器。 scale 可以取值 1, 2, 4, 8。
如果不指定 scale 值,则默认值为 1。section 可以指定任意的段寄存器作为段前缀,默认的
段寄存器在不同的情况下不一样。 如果你在指令中指定了默认的段前缀, 则编译器在目标代
码中不会产生此段前缀代码。
下面是一些例子:
-4(%ebp) :base=%ebp,displacement= -4,section 没有指定,由于 base=%ebp,所
以默认的 section=%ss,index,scale 没有指定,则 index 为 0。
foo(,%eax,4):index=%eax,scale=4,displacement=foo。其它域没有指定。这里默认
的 section=%ds。
foo(,1):这个表达式引用的是指针 foo 指向的地址所存放的值。注意这个表达式中没有
base 和 index ,并且只有一个逗号,这是一种异常语法,但却合法。
%gs:foo:这个表达式引用的是放置于%gs 段里变量 foo 的值。
如果 call 和 jump 操作在操作数前指定前缀“*” , 则表示是一个绝对地址调用/跳转, 也
就是说 jmp/call 指令指定的是一个绝对地址。 如果没有指定"*", 则操作数是一个相对地址base 和 index ,并且只有一个逗号,这是一种异常语法,但却合法。
%gs:foo:这个表达式引用的是放置于%gs 段里变量 foo 的值。
如果 call 和 jump 操作在操作数前指定前缀“*” , 则表示是一个绝对地址调用/跳转, 也
就是说 jmp/call 指令指定的是一个绝对地址。 如果没有指定"*", 则操作数是一个相对地址base 和 index ,并且只有一个逗号,这是一种异常语法,但却合法。
%gs:foo:这个表达式引用的是放置于%gs 段里变量 foo 的值。
如果 call 和 jump 操作在操作数前指定前缀“*” , 则表示是一个绝对地址调用/跳转, 也
就是说 jmp/call 指令指定的是一个绝对地址。 如果没有指定"*", 则操作数是一个相对地址base 和 index ,并且只有一个逗号,这是一种异常语法,但却合法。
%gs:foo:这个表达式引用的是放置于%gs 段里变量 foo 的值。
如果 call 和 jump 操作在操作数前指定前缀“*” , 则表示是一个绝对地址调用/跳转, 也
就是说 jmp/call 指令指定的是一个绝对地址。 如果没有指定"*", 则操作数是一个相对地址base 和 index ,并且只有一个逗号,这是一种异常语法,但却合法。
%gs:foo:这个表达式引用的是放置于%gs 段里变量 foo 的值。
如果 call 和 jump 操作在操作数前指定前缀“*” , 则表示是一个绝对地址调用/跳转, 也
就是说 jmp/call 指令指定的是一个绝对地址。 如果没有指定"*", 则操作数是一个相对地址base 和 index ,并且只有一个逗号,这是一种异常语法,但却合法。
%gs:foo:这个表达式引用的是放置于%gs 段里变量 foo 的值。
如果 call 和 jump 操作在操作数前指定前缀“*” , 则表示是一个绝对地址调用/跳转, 也
就是说 jmp/call 指令指定的是一个绝对地址。 如果没有指定"*", 则操作数是一个相对地址