寻址方式

  • 立即数寻址

  • 寄存器寻址

  • 存储器寻址

    • 直接寻址 : mov ax, [ 01000h ]; 直接在[]内给出一个内存地址

    • 寄存器间接寻址: mov ax ,[si]; 在[]以寄存器的值给出内存地址.

    • 寄存器相对寻址: mov ax,[si+0ch][]以寄存器的值和一个数相加之后作为内存地址.

      struct MyStruct{
         int n1;
         char ch;
         int n2;
      };
      MyStruct stc;
      stc.n1 = 0;
      stc.n2 = 10;
      //假设stc的内存首地址是0x1000
      // 以汇编形式访问结构体字段:
      mov bx , 0x1000; // bx保存了结构体首地址
      mov [bx+0] , 0; //stc.n1
      mov [bx+8] , 10;//stc.n2
    • 基址变址寻址: mov ax,[si+bx] 使用两个寄存器相加之和作为内存地址

      char szBuff[10];
      for(int i = 0; i<10;++i){
         szBuff[i] = 0;
      }
      // 假设szBuff首地址是0x1000
      mov si , 0x1000;
      xor bx,bx;

      for(int i =0;i<10;++i){
         // szBuff[i] = 0;
         mov [si+bx] , 0;
      inc bx;
      }
    • 相对基址变址寻址: mov ax,[si+bx+0ch] 使用[]内的表达式的相加之和作为内存地址.

    • 在16位汇编中, 要使用存储器寻址的时候, 如果希望用寄存器寻址, 那么只能使用si,di,bx,bp寄存器, 然后这些寄存器不能任意组合.

条件跳转指令

有有符号跳转和无符号跳转之分.

常见条件跳转指令:

  • 有符号跳转:

    • jg 大于

    • jge 大于等于

    • jl 小于

    • jle 小于等于

  • 无符号跳转

    • ja 大于, cf0 且 zf0则跳转

    • jae 大于等于 , cf ==0 则跳转

    • jb 小于, cf==1则跳转

    • jbe 小于等于, cf1 或 zf1则跳转

  • 不区分符号跳转

    • je zf==1 则跳转

    • jne zf==0 则跳转

32位汇编

第一个汇编项目


.386 ;告诉汇编器, 使用32位汇编的语法来编译
.model flat , stdcall ;默认使用平坦模式,默认使用stdcall的调用约定
option casemap:none


.code ; 定义一个代码段

sldkfjlaskdjfmain:
ret
 
end sldkfjlaskdjfmain; 指定程序入口点
end ; 结束代码段

masm汇编器的语法

  1. 每个asm源码文件中都以下面的指令打头:

    .386 ;告诉汇编器, 使用32位汇编的语法来编译
    .model flat , stdcall ;默认使用平坦模式,默认使用stdcall的调用约定
    option casemap:none
  2. 必须自己定义一个代码段, 定义代码段使用.code伪指令 , 汇编指令就写在.codeend之间

  3. 程序必须要有一个入口点.在C语言中, 就固定了是main函数. 在masm里面, 可以在代码段中使用end 标签的方式来指定入口点.

  4. 数据的定义必须放在数据段, 数据段使用.data指令来定义.

    .data ; 定义数据段
    .const ; 定义常量数据(不可修改的数据)
    .code ; 定义代码段
    1. 在数据段中定义数据, 可以使用d系列指令

      .data 
      ch db 'a'         ; 相当于 char ch='a';

      buff db 0,0,0,0 ; 相当于 char buff[]={0,0,0,0};

      str db "hello" , 0; 相当于 char str[]={'h','e','l','l','o' , 0 }; 也就是说,这里不会自动加上字符串结束符'\0'

      str2 db "hello\n" , 0; 在masm中没有转义字符.
      str2 db "hello", 0ah , 0 ; 0ah是'\n'

      ; 其它类型
      var1 dw 100 ; word类型
      var2 dd 100 ; dword类型

      ; dup用于重复定义数据 , dup前是一个重复的次数, dup圆括号内是需要重复的初始化值.
      arr dd 100 dup(0) ; int arr[100]={0};

汇编版本的helloworld


.386 ;告诉汇编器, 使用32位汇编的语法来编译
.model flat , stdcall ;默认使用平坦模式,默认使用stdcall的调用约定
option casemap:none ; 不区分大小写

; 包含名为`msvcrt.inc`头文件(c语言的所有库函数)
include msvcrt.inc
; 包含库文件
includelib msvcrt.lib

;include windows.inc
;include user32.inc
;includelib user32.lib

.data
g_str db "hello world",0dh,0ah, 0 ; \r\n==0d0a

.code ; 定义一个代码段

main:
push offset g_str;
call crt_printf
add esp , 4
  ret
 
end main; 说明程序入口点
end ; 结束代码段

汇编程序基础

三大程序结构

  • 顺序结构

  • 选择结构

    • 在c中, if else , switch

  • 循环结构

模拟选择结构

模拟if-else

int n =0;
scanf("%d",&n);

if( n == 1){
   printf("星期一\n");
}
else if(n==2){
   printf("星期二\n");
}
else if(n==3){
   printf("星期三\n");
}

汇编版本

.data 
n dd 0 ; 定义一个全局变量, 名字为n

.code
_main:
cmp n , 1
je _FLAG1
cmp n , 2
je _FLAG2
cmp n , 3
je _FLAG3
_FLAG1:
printf("星期一\n");  
  jmp _ENDIF
_FLAG2:
printf("星期二\n");
jmp _ENDIF
_FLAG3:
  printf("星期三\n");
_ENDIF:
end _main
end

模拟switch-case

switch( n )
{
   case 1: printf("星期1\n");break;
   case 2: printf("星期2\n");break;
   case 3: printf("星期3\n");break;
}

汇编版本1(和if-else的一样)

汇编版本1 : 使用跳转表

.386 ;告诉汇编器, 使用32位汇编的语法来编译
.model flat , stdcall ;默认使用平坦模式,默认使用stdcall的调用约定
option casemap:none ; 不区分大小写 ; 包含名为`msvcrt.inc`头文件(c语言的所有库函数)
include msvcrt.inc
; 包含库文件
includelib msvcrt.lib ;include windows.inc
;include user32.inc
;includelib user32.lib .data
g_str db "hello world",0dh,0ah, 0 ; \r\n==0d0a
str1 db "星期一",0dh,0ah,0
str2 db "星期2",0dh,0ah,0
str3 db "星期3",0dh,0ah,0 .code ; 定义一个代码段 main:
.code
jmp being
jmptable dd _FLAG1,_FLAG2,_FLAG3 ; 在code段定义数据
being:
mov eax , 1 ; ;
dec eax;
jmp [jmptable+eax*4]; 根据eax的值,来跳转不同的位置. _FLAG1:
invoke crt_printf, offset str1;
jmp _ENDIF
_FLAG2:
invoke crt_printf , offset str2;
jmp _ENDIF
_FLAG3:
invoke crt_printf ,offset str1;
_ENDIF: end main; 说明程序入口点
end ; 结束代码段

模拟循环结构

使用条件跳转模拟循环

int i =0;
while (i < 10)
{
   ++i;
}

汇编版本1:

    xor eax,eax ; 使用eax寄存器作为i
   
_WHILE:
   cmp eax , 10 ;
   jge _ENDWHILE
inc eax
jmp _WHILE
_ENDWHILE:

汇编版本2 : loop 循环, 该指令使用ecx作为默认寄存器, 保存着循环次数, loop指令执行之后, 会判断ecx的值是否等于0 , 如果等于了,就不会跳转, 如果没有等于, 就先将ecx递减1, 然后跳转

    mov ecx , 10; 
_WHILE: loop _WHILE ;

函数结构

  • 函数调用和函数返回语句call,ret

    • call 目标地址 - 调用函数的指令

      • 会将call指令的下一条指令的地址push到栈中.

      • 跳转到目标地址.

    • ret 返回指令

      • 其实就是pop eip ,call指令将一个返回地址保存到栈中, ret就默认把栈中的地址取出设置到eip这样就能回调函数的调用点了.

      • ret 字节数 - 返回时,顺便平衡指定字节栈空间.

  • 定义函数

    • 通过ret指令来回到函数的调用点.

  • 调用函数

    • 函数的传参是通过栈来完成的.

      • 调用函数之前, 先将实参压入栈中.

      • 进入函数之后, 就可以从栈中取出参数了.

      • 在传参的时候, 是从右往左依次将参数入栈,还是从左往右,需要有一个函数调用约定

        调用约定名 传参顺序 栈平衡者
        _cdecl - C调用约定 从右往左 函数外部
        _stdcall - 标准调用约定 从右往左 函数内部
        _thiscall - 对象调用 从右往左,this指针保存到ecx寄存器 函数内部
        fastcall - 快速调用约定 前两个参数通过ecx,edx来传递, 后面的参数从右往左依次入栈传递 函数内部
    • 通过call + 函数地址完成调用

  • 在函数内部定位栈中的参数

汇编2.汇编版本的helloworld的更多相关文章

  1. EJB2.0版本的HelloWorld

    EJB2.0版本的HelloWorld   虽然EJB3.1已经出来了,可是EJB2.0的项目还需要维护啊.下面写个简单EJB2.0的HelloWorld程序,练练手.   环境: JBoss 4.0 ...

  2. iOS汇编系列-汇编入门

    概述 汇编语言(Assembly Language)用符号代替了0和1,比机器语言更便于阅读和记忆. 但是同样汇编语言同样指令太多不便于记忆,就出现了高级语言.C\C++\Java\Swift等,更接 ...

  3. JDK-windows7环境变量配置-亲测版本 以及HelloWorld

    1.下载并安装jdk,假设安装1.6.0_45版本到C:\Program Files\Java,则安装完毕后,目录结构为: C:\PROGRAM FILES\JAVA├─jdk1.6.0_45│ ├─ ...

  4. ARM汇编初探---汇编代码中都有哪几类指令---ARM伪指令介绍

    要学习一个东西首先要把概念搞清楚,以下仅仅是自己的一些关于汇编的理解. 可运行文件里的01码是机器码,机器码不等于汇编码,尽管机器码能够非常easy翻译成汇编码. 汇编码中包括非常多汇编指令.伪指令和 ...

  5. 汇编 | x86汇编指令集大全(带注释)

    做mit-6.828的时候遇到了很多汇编知识,但是无奈学校还没学汇编,只能狠心啃啃硬骨头,在网上查到了很多的资料,归档!方便查看 ----------------------------------- ...

  6. 第二个hibernate Annotation版本的helloworld

    经过第一次的 hibernate  我发现每一个数据库表都对应了一个类,并且每一个类都要新建一个文件进行配置 很麻烦!  于是便出现了Annotation版本的hibernate. 具体如下: 1.同 ...

  7. Hibernate学习笔记1.2(Annotation版本的Helloworld)

    hibernate 3.0之后开始支持Annotation 接着1.1的项目 首先 需要创建model Teacher.java. package com.hw.hibernate.model; pu ...

  8. Go语言版本的helloworld

    新建一个project,然后建立一个main目录,在main目录下新建一个go类文件:main.go 内容如下: package main import "fmt" func ma ...

  9. Annotation版本的HelloWorld

    hiberante 的 annotation历史: 在hibernate3以后,开始支持Annotation; 先有hiberante再有JPA,有了JPA标准之后,hibernate写了Annota ...

随机推荐

  1. cas单点登录系统:客户端(client)详细配置(包含统一单点注销配置)

    最近一直在研究cas登录中心这一块的应用,分享一下记录的一些笔记和心得.后面会把cas-server端的配置和重构,另外还有这几天再搞nginx+cas的https反向代理配置,以及cas的证书相关的 ...

  2. 51Nod 1327 棋盘游戏 —— 延迟DP

    题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1327 看博客:https://www.cnblogs.com/Na ...

  3. Linux Bash 提示符的一些骚年操作

    当你在 Linux 环境下打开一个 Shell 终端时,会看到命令行中出现了类似下面的一个 Bash 提示符: 百牛信息技术bainiu.ltd整理发布于博客园[user@$host ~]$1[use ...

  4. VC++、MFC

    VC++.MFC最好的开源项目 介绍:介绍一下用VC++/MFC写的最好的开源项目. Sourceforge.net中有许多高质量的VC++开源项目,我列举了一些可以作为VC++程序员的参考. 正文: ...

  5. Oracle UNDO Tablespace size & Table Size

    Table Space Query select SEGMENT_NAME,bytes/1024/1024,a.* from dba_segments a UNDO Table Space Size ...

  6. 【WEB基础】HTML & CSS 基础入门(4)列表及其样式

    前面 网页中漂亮的导航.整齐规范的文章标题列表和图片列表等等.这些都是离不开HTML里一个重要的元素----列表,在HTML中有无序列表.有序列表和定义列表三种类型.其中,无序列表应用最为广泛,下面, ...

  7. hdu2476【区间DP,未完待续】

    好难搞得东西.... 题意都懒得写了,看题解的巨巨莫怪啊,未完待续未完待续,回去睡觉.

  8. python 闭包 闭包与装饰器之间的关系

    一.一个闭包的实际应用例子 def func(a, b): def inner(x): return a * x + b return inner inn = func(1, 1) print(inn ...

  9. bzoj 4403: 序列统计【lucas+组合数学】

    首先,给一个单调不降序列的第i位+i,这样就变成了单调上升序列,设原来数据范围是(l,r),改过之后变成了(l+1,r+n) 在m个数里选长为n的一个单调上升序列的方案数为\( C_m^n \),也就 ...

  10. 高级开发不得不懂的Redis Cluster数据分片机制

    Redis 集群简介 Redis Cluster 是 Redis 的分布式解决方案,在 3.0 版本正式推出,有效地解决了 Redis 分布式方面的需求. Redis Cluster 一般由多个节点组 ...