NASM汇编HelloWorld

一、Linux汇编介绍
1、DOS和Linux汇编主要不同的地方
DOS汇编中,大部分工作依靠21号中断(int 21h,DOS中断子程序)来完成,并且BIOS服务中断用int 10h(BIOS中断-显示器输出中断调用)和int 16h(BIOS中断-键盘输入中断调用);在linux中,所有的函数通过linux系统调用最终被内核处理,并且通过int 80h陷入内核代替用户空间执行,这称为linux的软中断。linux的系统调用比DOS更少但更实用。
linux是一个32位保护模式编程系统,因此我们能处理真正的现代的32位汇编,32位代码运行在flat(平板)内存模型,其基本意思就是你根本不用再担心段寄存器的处理,因为你不必用段地址来重写或者修改段寄存器,它的每个地址都是32位长,并包含一个偏移量。
x86的32位汇编代码中,你可以使用32位寄存器如eax,ebx,ecx,edx等,来代替16寄存器ax,bx,cx,dx等等。
DOS的16编程时代已经过时了,只有一些不舍得扔下386编程的一些老的黑客仍在用它,linux汇编更实用。(linux操作系统一部分由汇编代码编写,并且硬件驱动也常常离不开汇编代码,因为他是最靠近硬件的语言)

2、一个汇编程序的组成
一个简单的汇编代码通常分成下面三个段:
旁注:在编译器编译并链接生成可执行文件的过程中,会出现两个section的概念——
1)一个是在生成目标文件,通常是我们所说的.o文件,目标文件也是由多个section组成,我们通常叫这个section为“节”,这里的每个section的地址是静态偏移地址,是基于0的偏移地址,而在我们链接多个目标文件(.o)及库(静态库和动态库,关于这两者,详细请看ld手册)时,实际上是经过ld链接脚本的处理并进行重定位之后,
2)把每个目标文件中的各个section放到可执行文件的一个section中,这个section我们通常叫它段(例如.text节重定位之后生成.text段,.data节重定位生成.data段等等),详细请参考ld manual

.data section(节)
这个section主要存放初始化的数据,.data section包含利用像文件名、缓冲大小,并且还可以用EQU定义常量(constant),可以使用的一些指令如:DB,DW,DD,DQ,DT
例:
section .data
         message:                   db ‘Hello world!’      ;相当于char/unsigned char* Hello world!
         msglength:       equ 12          ; 字符串长度12字节
         buffersize:        dw 1024                     ;缓冲区大小1024个字长(相当于short类型)    

.bss section              ;未初始化section
;这个section存放未初始化数据,可以用RESB,RESW,RESD,RESQ和REST指令来为你的变量申请为初始化空间。
section .bss
         filename: resb 255                                        ;255字节
         number: resb 1
         bignum: resw 1
         realarray: resq 10

.text section      ;代码section
这个section用于存放用户代码,.text section必须从global _start开始,来告诉内核程序从什么地方开始执行(类似于C或JAVA中的main函数,这里指一个开始位置)
section .text
         global _start
_start:
         pop ebx                       ;这里是程序实际开始的地方
                   .
                   .
                   .
正如你所看到的,到目前为止,或者多或少都有一点DOS的味道,下面我们通过讲解linux系统调用之后,便可以完成你的第一个linux汇编程序了。

3、linux系统调用
linux系统调用和DOS系统调用并不完全一样:
1. 放系统调用号到eax中
2. 设置系统调用参数到ebx,ecx等
3. 调用相关中断(DOS:21h; linux:80h)
4. 返回结果通常保存在eax中
对于系统调用,x86有6个寄存器可以使用,分别是是ebx,ecx,edx,esi,edi,ebp,如果参数多于6个,ebx必须包含一个参数存放的地址,但我们通常不必担心,因为系统调用不大可能超过6个参数,更为激动的是,linux系统调用设计一贯都遵守这个原则。
下面是一些可能有帮助的例子:
move ax,1                           ;sys_exit系统调用号
mov ebx,0                           ;exit参数0,相当于exit(0)
int 80h                                  ;80中断,通常中软中断,调用它意思就是告诉内核,你处理它
接下来,你需要知道的是如何知道系统调用是什么,它们什么功能,有几个参数等等?首先,所有的系统调用和对应的系统调用号都可以在/usr/include/asm/unistd.h中找到,在调用int 80h之前,你需要将它们存入eax中。看一看系统调用表,可以看到比如sys_write(4)、sys_nice(34)和sys_exit(1),4、34、1表示对应的系统调用的系统调用号。

4、最简单的程序HELLO WORLD
; hello.asm
section .data ; 数据段声明
msg db "Hello, world!", 0xA ; 要输出的字符串
len equ $ - msg ; 字串长度

section .text ; 代码段声明
global _start ; 指定入口函数
_start: ; 在屏幕上显示一个字符串
;1、设置系统调用号4,采用软中断80可以陷入内核执行
;所有的系统调用和对应的系统调用号都可以在/usr/include/asm/unistd.h中找到
;4号系统调用号为write这个系统调用
mov eax, 4 ; 系统调用号(sys_write)

;2、设置系统调用参数
;man 2 write 可以查看write系统调用的功能
;write函数原型: ssize_t write(int fd,const void *buf,size_t count);
mov ebx, 1 ; 参数一:文件描述符(stdout)
mov ecx, msg ; 参数二:要显示的字符串
mov edx, len ; 参数三:字符串长度
int 0x80 ; 调用内核功能。软中断,陷入内核

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; 退出程序
;3、设置系统调用号1,采用软中断80可以陷入内核执行
mov eax, 1 ; 系统调用号(sys_exit)
;4、设置系统调用参数
mov ebx, 0 ; 参数一:退出代码
int 0x80 ; 调用内核功能

编译和运行方法:
[hadoop@sam1 test_sam]$ ls
hello.asm
[hadoop@sam1 test_sam]$ nasm -f elf hello.asm
[hadoop@sam1 test_sam]$ ls
hello.asm hello.o
[hadoop@sam1 test_sam]$ ld -s -o hello hello.o
[hadoop@sam1 test_sam]$ ls
hello hello.asm hello.o
[hadoop@sam1 test_sam]$ ./hello
Hello, world!
[hadoop@sam1 test_sam]$

命令说明:
nasm -f elf hello.asm-->汇编
****************************************************************************************************************************************************************
-f [format] Specifies the output file format. To see a list of valid output formats, use the -hf option.
nasm -hf可以查看到:
valid output formats for -f are (`*' denotes default):
* bin flat-form binary files (e.g. DOS .COM, .SYS)
ith Intel hex
srec Motorola S-records
aout Linux a.out object files
aoutb NetBSD/FreeBSD a.out object files
coff COFF (i386) object files (e.g. DJGPP for DOS)
elf32 ELF32 (i386) object files (e.g. Linux)
elf64 ELF64 (x86_64) object files (e.g. Linux)
as86 Linux as86 (bin86 version 0.3) object files
obj MS-DOS 16-bit/32-bit OMF object files
win32 Microsoft Win32 (i386) object files
win64 Microsoft Win64 (x86-64) object files
rdf Relocatable Dynamic Object File Format v2.0
ieee IEEE-695 (LADsoft variant) object file format
macho32 NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (i386) object files
macho64 NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (x86_64) object files
dbg Trace of all info passed to output stage
elf ELF (short name for ELF32)
macho MACHO (short name for MACHO32)
win WIN (short name for WIN32)
****************************************************************************************************************************************************************

ld -s -o hello hello.o-->链接;貌似不写-s这个选项也能成功!
****************************************************************************************************************************************************************
ld命令
ld combines a number of object and archive files, relocates their data and ties up symbol references. Usually the last step in compiling a program is to run ld.
参数
-o Use output as the name for the program produced by ld; if this option is not specified, the name a.out is used by default.
-s Omit all symbol information from the output file.
****************************************************************************************************************************************************************

参考资料:
NASM x86汇编入门指南
http://blog.csdn.net/flickedball/archive/2009/11/15/4812051.aspx

NASM helloworld实例
http://hi.baidu.com/wolfand11/blog/item/08a153ee0df56d202cf5348e.html

你可能感兴趣的:(汇编(NASM))