Chinaunix首页 | 论坛 | 博客
  • 博客访问: 27511
  • 博文数量: 4
  • 博客积分: 95
  • 博客等级: 民兵
  • 技术积分: 35
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-16 13:48
文章分类

全部博文(4)

文章存档

2012年(4)

分类:

2012-06-28 13:39:12

在 Linux 操作系统中,你有很多办法可以实现在屏幕上显示一个字符串,但最简洁的方式是使用 Linux 内核提供的系统调用。使用这种方法最大的好处是可以直接和操作系统的内核进行通讯,不需要链接诸如 libc 这样的函数库,也不需要使用 ELF 解释器,因而代码尺寸小且执行速度快。

我们分别使用nasm和gas两种汇编器来编译我们的程序,这样我们可以看到Intel和AT&T两种语法格式了。

使用的工具

当然首先我们需要汇编编译器nasm和gas。然后我们需要链接器-ld,因为汇编编译器是生成的只是object代码。

Linux是一个32位的,运行在保护模式下的操作系统,使用的是flat memory 模式,使用ELF格式的二进制代码。

一个程序可以划分为下面几个部分: .text,.data,.bss。.text是一些只读的代码,.data是可读可写的数据区,.bss则是可读可写的没有初始化的数据区。当然可以有其他一些标准的部分,也可以使用户自己定义的sections,但是我们这里不关心。一个程序至少有.text部分。

下面就是我们的第一个程序“hello,world”。我们给出两个版本,分别是nasm和gas两种。

NASM (hello.asm)
--------------
; hello.asm
section .data            ; 数据段声明
        msg db "Hello, world!", 0xA     ; 要输出的字符串
        len equ $ - msg                 ; 字串长度
section .text            ; 代码段声明
global _start            ; 指定入口函数
_start:                  ; 在屏幕上显示一个字符串
        mov edx, len     ; 参数三:字符串长度
        mov ecx, msg     ; 参数二:要显示的字符串
        mov ebx, 1       ; 参数一:文件描述符(stdout)
        mov eax, 4       ; 系统调用号(sys_write)
        int 0x80         ; 调用内核功能
                         ; 退出程序
        mov ebx, 0       ; 参数一:退出代码
        mov eax, 1       ; 系统调用号(sys_exit)
        int 0x80         ; 调用内核功能
        


对于nasm,下面的语法:

$ nasm -f elf hello.asm

然后我们就要使用这个object文件来生成可执行代码。这里使用链接器链接:

$ ld -s -o hello hello.o

这样我们就获得了我们的可以执行的代码“hello,world”。
       
     
AT&T 格式

#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       # 调用内核功能

编译命令一样:(假设汇编源文件名为:hello.s)

$ as hello.s -o hello.o

$ ld hello.o -o hello



附录:
linux2.6.28内核源码:

sys_write

376 asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_    t count)
377 {
378         struct file *file;
379         ssize_t ret = -EBADF;
380         int fput_needed;
381
382         file = fget_light(fd, &fput_needed);
383         if (file) {
384                 loff_t pos = file_pos_read(file);
385                 ret = vfs_write(file, buf, count, &pos);
386                 file_pos_write(file, pos);
387                 fput_light(file, fput_needed);
388         }
389
390         return ret;
391 }

sys_exit

1146 asmlinkage long sys_exit(int error_code)
1147 {     
1148         do_exit((error_code&0xff)<<8);
1149 }


 
阅读(1436) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~