NASM概述

WWW: http://www.drpaulcarter.com/pcasm

mov dest  src,mov 操作相当于高级语言中的分配操作。可能相当于int i =1之类的。
mov操作不能对内存中的两个数进行操作,且被操作的两个数位数要相同,al和bh就不能被操作。

下面是一些例子:
mov eax, 3 ; store 3 into EAX register (3 is immediate operand)
mov bx, ax ; store the value of AX into the BX register
The ADD instruction is used to add integers.
add eax, 4 ; eax = eax + 4
add al, ah ; al = al + ah
The SUB instruction subtracts integers.
sub bx, 10 ; bx = bx - 10
sub ebx, edi ; ebx = ebx - edi
The INC and DEC instructions increment or decrement values by one.
Since the one is an implicit operand, the machine code for INC and DEC is
smaller than for the equivalent ADD and SUB instructions.
inc ecx ; ecx++
dec dl ; dl--

Directive(伪指令)
这是汇编语言的指令,不是cpu的指令,不会被编译成机器语言。主要是指示汇编去做什么操作或者在汇编语言之间传递信息。主要有以下作用:
 define constants
 define memory to store data into
 group memory into segments
 conditionally include source code
 include other files

NASM也有预处理操作,和C一样,不同的是,C用#而NASM用%.

伪指令有以下几个:
equ  symbol equ value  定义一个常量,可以在汇编程序中使用,但不能被重定义。
%    %define SIZE 100
     mov eax, SIZE     宏操作,和equ的区别是,SIZE可以被重定义。

数据伪指令有2种,一种是只分配空间,RESX,另一种是既分配空间还指定初值,DX。
X是下表中的Letter对应的字母,以分配空间确定。

 Unit  Letter
 byte B
 word W
 double word D
 quad word Q
 ten bytes T
 
下面是一些例子。
L1 db 0 ; byte labeled L1 with initial value 0
L2 dw 1000 ; word labeled L2 with initial value 1000
L3 db 110101b ; byte initialized to binary 110101 (53 in decimal)
L4 db 12h ; byte initialized to hex 12 (18 in decimal)
L5 db 17o ; byte initialized to octal 17 (15 in decimal)
L6 dd 1A92h ; double word initialized to hex 1A92
L7 resb 1 ; 1 uninitialized byte
L8 db "A" ; byte initialized to ASCII code for A (65)
双引号和单引号没有区别。
连续的变量在内存中被连续的存储,L2紧接着L1存储。
L9 db 0, 1, 2, 3 ; defines 4 bytes
L10 db "w", "o", "r", ’d’, 0 ; defines a C string = "word"
L11 db ’word’, 0 ; same as L10
对于大的序列操作,NASM有TIMES伪指令。
L12 times 100 db 0 ; equivalent to 100 (db 0)’s
L13 resw 100 ; reserves room for 100 words
变量的调用有2种方式,只是变量,表示的是地址,[变量],表示的是该地址的数据。

1 mov al, [L1] ; copy byte at L1 into AL
2 mov eax, L1 ; EAX = address of byte at L1
3 mov [L1], ah ; copy AH into byte at L1
4 mov eax, [L6] ; copy double word at L6 into EAX
5 add eax, [L6] ; EAX = EAX + double word at L6
6 add [L6], eax ; double word at L6 += EAX
7 mov al, [L6] ; copy first byte of double word at L6 into AL
第七行显示了NASM的一个特性,汇编编译器不知道变量的类型。这就要程序员考虑是否正确。
考虑下面的指令:mov [L6], 1 ; store a 1 at L6
这将会导致“类型不确定”的错误。可以指定类型:
mov dword [L6], 1 ; store a 1 at L6
其他的指定类型有:BYTE, WORD, QWORD and TWORD。
TWORD是10个字节长度,浮点型协处理器要用到此类型。

I/O
NASM也有自己的I/O处理函数,像C语言一样,这样比直接用汇编写要方便。
要使用这些函数,必须用语句 %include "asm_io.inc" 包含头文件。
调用的函数主要操作EAX中的数据,用CALL调用。
print_int
prints out to the screen the value of the integer stored in EAX.
print_char
prints out to the screen the character whose ASCII value stored in AL.
print_string
prints out to the screen the contents of the string at the address stored in EAX. The string must be a Ctype string (i.e. null terminated).
print_nl
prints out to the screen a new line character.
read_int
reads an integer from the keyboard and stores it into the EAX register.
read_char
reads a single character from the keyboard and stores its ASCII code into the EAX register.

DEBUG
作者也写了DEBUG的函数,我们也可以通过 %include "asm_io.inc" 来调用。
dump_regs
This macro prints out the values of the registers (in hexadecimal) of the computer to stdout (i.e. the screen). It also displays the bits set in the FLAGS register. For example, if the zero flag is 1, ZF is displayed. If it is 0, it is not displayed. It takes a single integer argument that is printed out as well. This can be used to distinguish the output of different dump_regs commands.
dump_mem
This macro prints out the values of a region of memory (in hexadecimal) and also as ASCII characters. It takes three comma delimited arguments. The first is an integer that is used to label the output (just as dump_regs argument). The second argument is the address to display. (This can be a label.) The last argument is the number of 16-byte paragraphs to display after the address. The memory displayed will start on the first paragraph boundary before the requested address.
dump_stack
This macro prints out the values on the CPU stack.  The stack is organized as double words and this routine displays them this way. It takes three comma delimited arguments. The first is an integer label (like dump_regs). The second is the number of double words to display below the address that the EBP register holds and the third argument is the number of double words to display above the address in EBP.
dump_math
This macro prints out the values of the registers of the math coprocessor. It takes a single integer argument that is used to label the output just as the argument of dump_regs does.

编一个程序
因为现在很少用纯汇编编程序,所以,例子都是和C/C++语言结合的。第一个例子是通过C语言程序调用的,C语言程序如下:
int main()
{
int ret status ;
ret status = asm_main();
return ret status ;
}
程序调用asm_main(),asm_main()是纯汇编程序。程序如下:
1 ; file: first.asm
2 ; First assembly program. This program asks for two integers as
3 ; input and prints out their sum.
4 ;
5 ; To create executable using djgpp:
6 ; nasm -f coff first.asm
7 ; gcc -o first first.o driver.c asm_io.o
8
9 %include "asm_io.inc"
10 ;
11 ; initialized data is put in the .data segment
12 ;
13 segment .data
14 ;
15 ; These labels refer to strings used for output
16 ;
17 prompt1 db "Enter a number: ", 0 ; don’t forget null terminator
18 prompt2 db "Enter another number: ", 0
19 outmsg1 db "You entered ", 0
20 outmsg2 db " and ", 0
21 outmsg3 db ", the sum of these is ", 0
22
23 ;
24 ; uninitialized data is put in the .bss segment
25 ;
26 segment .bss
27 ;
28 ; These labels refer to double words used to store the inputs
29 ;
30 input1 resd 1
31 input2 resd 1
32
33 ;
34 ; code is put in the .text segment
35 ;
36 segment .text
37 global _asm_main
38 _asm_main:
39 enter 0,0 ; setup routine
40 pusha
41
42 mov eax, prompt1 ; print out prompt
43 call print_string
44
45 call read_int ; read integer
46 mov [input1], eax ; store into input1
47
48 mov eax, prompt2 ; print out prompt
49 call print_string
50
51 call read_int ; read integer
52 mov [input2], eax ; store into input2
53
54 mov eax, [input1] ; eax = dword at input1
55 add eax, [input2] ; eax += dword at input2
56 mov ebx, eax ; ebx = eax
57
58 dump_regs 1 ; print out register values
59 dump_mem 2, outmsg1, 1 ; print out memory
60 ;
61 ; next print out result message as series of steps
62 ;
63 mov eax, outmsg1
64 call print_string ; print out first message
65 mov eax, [input1]
66 call print_int ; print out input1
67 mov eax, outmsg2
68 call print_string ; print out second message
69 mov eax, [input2]
70 call print_int ; print out input2
71 mov eax, outmsg3
72 call print_string ; print out third message
73 mov eax, ebx
74 call print_int ; print out sum (ebx)
75 call print_nl ; print new-line
76
77 popa
78 mov eax, 0 ; return back to C
79 leave
80 ret
13行定义了一个内存块用来存放数据,用.DATA表示(数据段)。只有初始化的数据可以在这里定义。17~21行,一些字符串被声明,它们将被C语言的库函数打印,所以必须以NULL(ASCII 码0)结尾。记住,0和'0'有区别。
没有被初始化的数据在.BSS中声明。这也是一个堆栈段(26行)。这将在以后讨论。
代码段是.TEXT,注意38行,_asm_main前面有个下划线,这是C语言编译的时候要用的,但是只是在WINDOWS平台下要这样,LINUX下不用考虑。
37行的glabal伪指令指定_asm_main可以被外部程序调用。默认的,函数只能被本模块调用。相当于C语言的extern。

要编译程序,就要下载NASM,GCC,WINDOWS版本就按照源代码注释中的命令编译。LINUX版本,先把37,38行的_asm_main前面的下划线去掉。在修改编译命令参数:nasm -f elf first.asm

NASM可以用 -l listfile 将汇编过程打印出来。如54~56行对应如下:
94 0000002C A1[00000000] mov eax, [input1]
95 00000031 0305[04000000] add eax, [input2]
96 00000037 89C3 mov ebx, eax
第一列为list文件的行号,第二列是偏移量,第三列为语句对应的机器码(代码段)或者ASCII码(数据段)。第四列是对应的源程序。注意,偏移量很可能不是数据在整个程序中的偏移量。编译的时候是一个模块的,LINK的时候有多个模块的话,偏移量就不同了。
还要注意看95行,input2的地址是04000000,但是因为数据在内存中是顺序排列的,那应该是00000004,这是怎么回事呢?原来,不同的CPU把数据存到内存中有不同的方法。IBM 大型机, 很多RISC处理器和Motorola的处理器,都是顺序排列的,00000004就排列为00000004。而INTEL的处理器是倒过来排列的,00000004排列为04000000。平时编程也不要求太注意,但如果程序中有二进制数的处理,并且这个处理要在不同的处理器平台上执行,比如从INTEL机器上取出二进制数,在IBM机器上转换成整数,处理完毕再传回INTEL机器上,就可能得到错误的数据。

最后是汇编程序结构,结构记住了,以后编程序就是写不同的处理语句了。
1 %include "asm_io.inc"
2 segment .data
3 ;
4 ; initialized data is put in the data segment here
5 ;
6
7 segment .bss
8 ;
9 ; uninitialized data is put in the bss segment
10 ;
11
12 segment .text
13 global _asm_main
14 _asm_main:
15 enter 0,0 ; setup routine
16 pusha
17
18 ;
19 ; code is put in the text segment. Do not modify the code before
20 ; or after this comment.
21 ;
22
23 popa
24 mov eax, 0 ; return back to C
25 leave
26 ret

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值