代码改变世界

【转】linux下汇编开发 tutorial

2010-06-18 12:58  caibing  阅读(240)  评论(0)    收藏  举报

本文主要参考:

http://www.ibm.com/developerworks/cn/linux/l-assembly/

 

上来直接看例子 Hello World

代码
#hello.s
.data # 数据段声明
msg : .string
"Hello, world!\\n" # 要输出的字符串
len = . - msg # 字串长度

.text # 代码段声明

.global _start # 指定入口函数
_start: # 在屏幕上显示一个字符串
movl $len, %edx # 参数三:字符串长度
movl $msg, %ecx # 参数二:要显示的字符串
movl $
1, %ebx # 参数一:文件描述符(stdout)
movl $
4, %eax # 系统调用号(sys_write)
int $0x80 # 调用内核功能

# 退出程序
movl $
0,%ebx # 参数一:退出代码
movl $
1,%eax # 系统调用号(sys_exit)
int $0x80 # 调用内核功能

 

section:

Linux 是一个运行在保护模式下的 32 位操作系统,采用 flat memory 模式,目前最常用到的是 ELF 格式的二进制代码。一个 ELF 格式的可执行程序通常划分为如下几个部分:.text、.data 和 .bss,其中 .text 是只读的代码区,.data 是可读可写的数据区,而 .bss 则是可读可写且没有初始化的数据区。代码区和数据区在 ELF 中统称为 section,根据实际需要你可以使用其它标准的 section,也可以添加自定义 section,但一个 ELF 可执行程序至少应该有一个 .text 部分。

 

系统调用:

这个应该是我们比较关注的,通过软中断进行系统调用。

跟32位系统一样,

1在%eax上我们首先填入对应的 系统调用号(调用系统的那个函数)

2然后按ebx,ecx,edx,esi,edi顺序作为参数,进行赋值

3执行 int 80 调用系统内核

4执行返回值放在eax中

 

gcc内联汇编

  • 变量b是输出操作数,通过%0来引用,而变量a是输入操作数,通过%1来引用。
  • 输入操作数和输出操作数都使用r进行约束,表示将变量a和变量b存储在寄存器中。输入约束和输出约束的不同点在于输出约束多一个约束修饰符'='。
  • 在内联汇编语句中使用寄存器eax时,寄存器名前应该加两个'%',即%%eax。内联汇编中使用%0、%1等来标识变量,任何只带一个'%'的标识符都看成是操作数,而不是寄存器。
  • 内联汇编语句的最后一个部分告诉GCC它将改变寄存器eax中的值,GCC在处理时不应使用该寄存器来存储任何其它的值。
  • 由于变量b被指定成输出操作数,当内联汇编语句执行完毕后,它所保存的值将被更新。
  •  

    /* inline.c */

    int main()
    {
    int a = 10, b = 0;
    __asm__ __volatile__("movl %1, %%eax;\\n\\r"
    "movl %%eax, %0;"
    :
    "=r"(b) /* 输出 */
    :
    "r"(a) /* 输入 */
    :
    "%eax"); /* 不受影响的寄存器 */

    printf(
    "Result: %d, %d\\n", a, b);
    }