博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
汇编学习笔记(9)-汇编程序的基本语法(NASM)
阅读量:5249 次
发布时间:2019-06-14

本文共 3120 字,大约阅读时间需要 10 分钟。

前言

  从本博文开始,我将主要学习NASM的语法格式,辅以MASM语法的相关了解

 

一个最简单的helloword 

; 功能描述 hellowordorg 07c00h ; 告诉编译器程序加载到7c00处,否则strMess位置的计算会出错的section .data     strMess: db "Hello, OS world!"     strlen equ $-strMess       ; 计算 strmess的长度 section .text    mov ax, strMess    mov bp, ax      ; ES:BP = 串地址    mov cx, strlen  ; CX = 串长度    mov ax, 01301h  ; AH = 13, AL = 01h    mov bx, 000ch   ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)    mov dl, 0    int 10h ; 10h 号中断    ret    jmp $ ; 无限循环

 流程控制

  1. if-else

    if-else 语句其实就是 cmp +  条件判断语句(如, je,ja,jb jne...)语句的组合

      原理: 1. 使用cmp来调整标记寄存器的的标记位

          2. 使用对应的条件判断指令来实现条件转跳,条件转跳指令会根据CMP指令对标志寄存器进行判断从而根据结果进行转跳

  例子:

mov ax, 2        cmp ax, 2        je a            ; if( eax = 2)        jmp  exit        ;elsea:      cmp ax, 1        ja b            ; if(eax > 1)        jmp  exit        ;elseb:      cmp ax, 3               jb c            ; if(eax < 3)        jmp  exit        ;elsec:

 

   2. while 和 for 循环

      while是使用了loop指令,loop指令就是判断CX是否为0,如果cx=0,那么啥都不做,如果cx 不等于 0 则 cx-- 然后转跳

   例子 

; while循环         mov cx, 10        mov bx, 0add:    add bx,1        loop add        ;  while(ecx != 0)

 

 调用子程序

       调用子程序其实不像C/C++那样有明确的界限,你可以使用任意的过程转跳指令去调用子程序,可以用非条件转移指令jmp也可以使用条件转移指令 je ja jb 等等,我现在所说的就是一般意义上用到的子程序调用指令 call和ret、retf。

       Call和jmp一样也分为段内和段间调用,对应的返回函数就分别是ret和retf,ret是段内返回,retf就是段间返回。

       Call和jmp的区别在于 call指令在jmp之前将当前地址给压栈了。

;段内调用Call:       Push ip            Jmp newipRet         pop ip;段间转移Call:       Push cs            Push ip       Jmpnewcs:newipRetf:      pop ip           Pop cs

 具体语法MASM和NASM是略有不同的 

MASM:

段内:              Call sub1      ; sub1是子过程              Call bx              Call [bx]              Call var         ; var是变量       段间:              Call sub1              Call far ptr sub1              Call dword ptr [bx]              Call var

        masm 有proc伪指令,用于声明过程调用语句,具体语法如下  

过程调用名  PROC [NEAR|FAR]....过程调用名 ENDP

 

  所以MASM可以显式的指明过程调用需要的是段内还是段间调用。 

 

NASM

段内:              Call sub1         Call 立即数              Call bx         Call var        段间:              Call far [bx]              Call 立即数:立即数              Call dword var 

       我不清楚nasm是否能针对标签识别出是段内和段间调用,但是我没发现显式声明使用标签的段间调用指令,但是我看到有博客说,nasm的16位汇编模式是没有段这个概念。我猜意思可能是段这个概念需要编程者自己去管理,nasm认为所有代码都在同一个段内。

 

参数传递

  汇编的参数传递是很灵活,具体只要调用方和被调用方约定好基本是随便传递,基本有三种方式

  1. 寄存器传递参数

  2.内存传递参数

  3.堆栈传递参数

  其中有几点需要注意

  1. 环境的保护,意思是在子过程中肯定要用到标志寄存器和一些其他寄存器,但是如果这里面有调用者重要的信息的话数据就被破坏了会导致调用者的异常。

  2. 数据的清理,比如使用堆栈传递数据,使用完之后由调用者清理还是被调用者清理。

  具体可以看一下c/c++的几个调用约定,stdcall fastcall 等等。。

 

 最后引用一段从网上的一个文档中看到的话,不过seg和wrt只有在编译格式是obj的时候才能用。  

《nasm中文手册》 3.6 `SEG'和`WRT'   当写很大的16位程序时,必须把它分成很多段,这时,引用段内一个符号的  地址的能力是非常有必要的,NASM提供了'SEG'操作符来实现这个功能。   'SEG'操作符返回符号所在的首选段的段基址,即一个段基址,当符号的偏  移地址以它为参考时,是有效的,所以,代码:              mov     ax,seg symbol              mov     es,ax              mov     bx,symbol总是在'ES:BX'中载入一个指向符号'symbol'的有效指针。而事情往往可能比这还要复杂些:因为16位的段与组是可以相互重叠的,你通常可能需要通过不同的段基址,而不是首选的段基址来引用一个符号,NASM可以让你这样做,通过使用'WRT'关键字,你可以这样写:              mov     ax,weird_seg        ; weird_seg is a segment base              mov     es,ax              mov     bx,symbol wrt weird_seg会在'ES:BX'中载入一个不同的,但功能上却是相同的指向'symbol'的指针。

  

 

 

 

转载于:https://www.cnblogs.com/alwaysking/p/8687441.html

你可能感兴趣的文章
Struts框架----进度1
查看>>
783. Minimum Distance Between BST Node
查看>>
剑指Offer——合并两个排序的链表
查看>>
剑指Offer——机器人的运动范围
查看>>
day01_Sock Merchant
查看>>
Round B APAC Test 2017
查看>>
Office 365 系列一 ------- 如何单个安装Office 客户端和Skype for business
查看>>
MySQL 字符编码问题详细解释
查看>>
perl 学习笔记
查看>>
31 Days of Windows Phone
查看>>
poj 1184(聪明的打字员)
查看>>
Ubuntu下面安装eclipse for c++
查看>>
C#压缩或解压(rar和zip文件)
查看>>
让IE浏览器支持CSS3圆角属性的方法
查看>>
巡风源码阅读与分析---nascan.py
查看>>
LiveBinding应用 dataBind 数据绑定
查看>>
Linux重定向: > 和 &> 区别
查看>>
nginx修改内核参数
查看>>
【欧拉函数模板题】最大公约数
查看>>
IOS做天气预报
查看>>