免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 975 | 回复: 0
打印 上一主题 下一主题

GNU汇编总结5 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-05-29 15:05 |只看该作者 |倒序浏览

# 九,使用函数                                          
GNU汇编语言定义函数的语法:
.type 标签(也就是函数名), @function
ret    返回到调用处
# 十,linux系统调用                                          
linux系统调用的中断向量为0x80
1, 系统调用标识存放在%eax中
2, 系统调用输入值:
     EBX     第一个参数
     ECX     第二个参数
     EDX     第三个参数
     ESI     第四个参数
     EDI     第五个参数
   
     需要输入超过6个输入参数的系统调用, EBX指针用于保存指向输入参数内存位置的指针, 输入参数按照连续的的顺序
     存储, 系统调用的返回值存放在EAX中
   
# 十一,汇编语言的高级功能
                                          
1,gnu内联汇编的语法:
asm或__asm__("汇编代码");
指令必须包含在引号里
如果包含的指令超过一行 必须使用新行分隔符分隔
使用c全局变量, 不能在内联汇编中使用局部变量, 注意在汇编语言代码中值被用做内存位置, 而不是立即数值
如果不希望优化内联汇编, 则可以volatile修饰符如:__asm__ volatile("code");
2,GCC内联汇编的扩展语法
__asm__("assembly code":output locations:input operands:changed registers);
第一部分是汇编代码
第二部分是输出位置, 包含内联汇编代码的输出值的寄存器和内存位置列表
第三部分是输入操作数,包含内联汇编代码输入值的寄存器和内存位置的列表
第四部分是改动的寄存器, 内联汇编改变的任何其他寄存器的列表
这几个部分可以不全有, 但是没有的还必须使用:分隔
1, 指定输入值和输出值, 输入值和输出值的列表格式为:
"constraint"(variable), 其中variable是程序中声明的c变量, 在扩展asm格式中, 局部和全局变量都可以使用,
使用constrant(约束)定义把变量存放到哪(输入)或从哪里传送变量(输出)
约束使用单一的字符, 如下:
约束                                   描述
a                         使用%eax, %ax, %al寄存器
b                         使用%ebx, %bx, %bl寄存器
c                         使用%ecx, %cx, %cl寄存器
d                         使用%edx, %dx, %dl寄存器
S                         使用%esi, %si寄存器
D                         使用%edi, %di寄存器
r                         使用任何可用的通用寄存器
q                         使用%eax, %ebx, %ecx,%edx之一
A                         对于64位值使用%eax, %edx寄存器
f                         使用浮点寄存器
t                         使用第一个(顶部)的浮点寄存器
u                         使用第二个浮点寄存器
m                         使用变量的内存位置
o                         使用偏移内存位置
V                         只使用直接内存位置
i                         使用立即整数值
n                         使用值已知的立即整数值
g                         使用任何可用的寄存器和内存位置
除了这些约束之外, 输出值还包含一个约束修饰符:
输出修饰符                             描述
+                         可以读取和写入操作数
=                         只能写入操作数
%                         如果有必要操作数可以和下一个操作数切换
&                         在内联函数完成之前, 可以删除和重新使用操作数
如:
__asm__("assembly code": "=a"(result):"d"(data1),"c"(data2));
把c变量data1存放在edx寄存器中, 把c变量data2存放到ecx寄存器中, 内联汇编的结果
将存放在eax寄存器中, 然后传送给变量result
在扩展的asm语句块中如果要使用寄存器必须使用两个百分号符号
不一定总要在内联汇编代码中指定输出值, 一些汇编指令假定输入值包含输出值, 如movs指令
其他扩展内联汇编知识:
1, 使用占位符
     输入值存放在内联汇编段中声明的特定寄存器中, 并且在汇编指令中专门使用这些寄存器.
     虽然这种方式能够很好的处理只有几个输入值的情况, 但对于需要很多输入值的情况, 这
     中方式显的有点繁琐. 为了帮助解决这个问题, 扩展asm格式提供了占位符, 可以在内联
     汇编代码中使用它引用输入和输出值.
   
     占位符是前面加上百分号的数字, 按照内联汇编中列出的每个输入和输出值在列表中的位置,
     每个值被赋予从0开始的地方. 然后就可以在汇编代码中引用占位符来表示值。
   
   
     如果内联汇编代码中的输入和输出值共享程序中相同的c变量, 则可以指定使用占位符作为
     约束值, 如:
     __asm__("imull %1, %0"
             : "=r"(data2)
             : "r"(data1), "0"(data2));
     如输入输出值中共享相同的变量data2, 而在输入变量中则可以使用标记0作为输入参数的约束
2, 替换占位符
     如果处理很多输入和输出值, 数字型的占位符很快就会变的很混乱, 为了使条理清晰 ,GNU汇编
     器(从版本3.1开始)允许声明替换的名称作为占位符.替换的名称在声明输入值和输出值的段中
     定义, 格式如下:
     %[name]"constraint"(variable)
     定义的值name成为内联汇编代码中变量的新的占位符号标识, 如下面的例子:
     __asm__("imull %[value1], %[value2]"
             : [value2] "=r"(data2)
             : [value1] "r"(data1), "0"(data2));
3, 改动寄存器列表
     编译器假设输入值和输出值使用的寄存器会被改动, 并且相应的作出处理。程序员不需要在改动的
     寄存器列表中包含这些值, 如果这样做了, 就会产生错误消息. 注意改动的寄存器列表中的寄存器
     使用完整的寄存器名称, 而不像输入和输出寄存器定义的那样仅仅是单一字母。 在寄存器名称前面
     使用百分号符号是可选的。
   
     改动寄存器列表的正确使用方法是, 如果内联汇编代码使用了没有被初始化地声明为输入或者输出
     值的其他任何寄存器 , 则要通知编译器。编译器必须知道这些寄存器, 以避免使用他们。如:
     int main(void) {
        int data1 = 10;
        int result = 20;
      
        __asm__("movl %1, %%eax\n\t"
                "addl %%eax, %0"
                : "=r"(result)
                : "r"(data1), "0"(result)
                : "%eax");
        printf("The result is %d\n", result);
        return 0;
     }
   
4, 使用内存位置
     虽然在内联汇编代码中使用寄存器比较快, 但是也可以直接使用c变量的内存位置。 约束m用于引用输入值
     和输出值中的内存位置。 记住, 对于要求使用寄存器的汇编指令, 仍然必须使用寄存器, 所以不得不定义
     保存数据的中间寄存器。如:
     int main(void) {
        int dividentd = 20;
        int divisor = 5;
        int result;
      
        __asm__("divb %2\n\t"
                "movl %%eax, %0"
                : "=m"(result)
                : "a"(dividend), "m"(divisor));
        printf("The result is %d\n", result);
        return 0;
     }
   
5, 处理跳转
     内联汇编语言代码也可以包含定义其中位置的标签。 可以实现一般的汇编条件分支和无条件分支, 如:
     int main(void) {
        int a = 10;
        int b = 20;
        int result;
      
        __asm__("cmp %1, %2\n\t"
                "jge greater\n\t"
                "movl %1, %0\n\t"
                "jmp end\n"
                "greater:\n\t"
                "movl %2, %0\n"
                "end:"
                :"=r"(result)
                :"r"(a), "r"(b));
        printf("The larger value is %d\n", result);
        return 0;
     }
   
     在内联汇编代码中使用标签时有两个限制。 第一个限制是只能跳转到相同的asm段内的标签,
     不能从-个asm段跳转到另一个asm段中的标签。第二个限制更加复杂一点。 以上程序使用
     标签greater和end。 但是, 这样有个潜在的问题, 查看汇编后的代码清单, 可以发现内联
     汇编标签也被编码到了最终汇编后的代码中。 这意味着如果在c代码中还有另一个asm段, 就
     不能再次使用相同的标签, 否则会因为标签重复使用而导致错误消息。还有如果试图整合使用
     c关键字(比如函数名称或者全局变量)的标签也会导致错误。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/86876/showart_1947309.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP