选择编译器

nasm?fasm?yasm?还是masm、gas或其他?

前面三个是免费开源的汇编编译器,总体上来讲都使用Intel的语法。yasm是在nasm的基础上开发的,与nasm同宗。由于使用了相同的语法,因此nasm的代码可以直接用yasm来编译。

yasm虽然更新较慢,但对nasm一些不合理的地方进行了改良。从这个角度来看,yasm比nasm更优秀些,而nasm更新快,能支持更新的指令集。在Windows平台上,fasm是另一个不错的选择,平台支持比较好,可以直接用来开发Windows上的程序,语法也比较独特。在对Windows程序结构的支持上,fasm是3个免费的编译器里做得最好的。

masm是微软发布的汇编编译器,现在已经停止单独发布,被融合在Visual Studio产品中。gas是Linux平台上的免费开源汇编编译器,使用AT&T的汇编语法,使用起来比较麻烦。

由于本书的例子是在祼机上直接运行,因此笔者使用nasm,因为它的语法比较简洁,使用方法简单,更新速度非常快。不过如果要是用nasm来写Windows程序则是比较痛苦的,这方面的文档很少。

从nasm的官网可以下载最新的版本:http://www.nasm.us/pub/nasm/releasebuilds/?C=M,也可以浏览和下载其文档:http://www.nasm.us/docs.php。

机器语言

一条机器指令由相应的二进制数标识,直接能被机器识别。在汇编语言出现之前,使用机器指令编写程序是直接将二进制数输入计算机中。

C语言中的c=a+b在机器语言中应该怎样表达?

这是一个很麻烦的过程,a、b和c都是变量,在机器语言中应该怎样表达?C语言不能直接转换为机器语言,要先由C编译器译出相当的assembly,然后再由assembler生成机器指令,最终再由链接器将这些变量的地址定下来。

我们来看看怎样转化机器指令。首先用相应的汇编语言表达出来。

mov eax, [a]               ; 变量 a 的值放到 eax寄存器中

add eax, [b]                ;执行 a+b

mov [c], eax                ;放到 c中

在x86机器中,如果两个内存操作数要进行加法运算,不能直接相加,其中一方必须是寄存器,至少要将一个操作数放入寄存器中。这一表达已经是最简单形式了,实际上当然不止这么简单,还要配合程序的上下文结构。如果其中一个变量只是临时性的,C编译器可能会选择不放入内存中。那么这些变量是局部变量还是外部变量呢?编译器首先要决定变量的地址。

mov eax, [ebp-4]                ;变量 a是局部变量

add eax, [ebp-8]                ;执行 a+b,变量b也是局部变量

mov [0x0000001c], eax          ;放到 c中,变量c可能是外部变量

变量a和b是在stack上。在大多数的平台下,变量c会放入到.data节,可是在进行链接之前,c的地址可能只是一个偏移量,不是真正的地址,链接器将负责用变量c的真正地址来代替这个偏移值。

上面的汇编语言译成机器语言为

8b 45 fc                 ;对应于  mov eax, [ebp-4]

03 45 f8                 ; 对应于  add eax, [ebp-8]

a3 1c 00 00 00         ; 对应于  mov [0x0000001c], eax

x86机器是CISC(复杂指令集计算)体系,指令的长度是不固定的,比如上述前面两条指令是3字节,最后一条指令是5字节。

x86机器指令长度最短1字节,最长15字节。

最后,假定.data节的基地址是0x00408000,那么变量c的地址就是0x00408000+0x1c = 0x0040801c,经过链接后,最后一条机器指令变成

a3 1c 80 40 00         ; 原始汇编表达形式:  mov [c], eax

指令同样采用little-endian存储序列,从低到高依次存放a3 1c 80 40 00字节,其中1c 80 40 00是地址值0x0040801c的little-endian字节序排列。

Hello world

按照惯例,我们先看看“Hello, World”程序的汇编版。

实验2-1:hello world程序

下面的代码相当于C语言main()里的代码。

代码清单2-1(topic02\ex2-1\setup.asm):

main:                                                       ;这是模块代码的入口点。

mov si, caller_message

call puts                                                     ;打印信息

mov si, current_eip

mov di, caller_address

current_eip:

call get_hex_string                                       ;转换为 hex

mov si, caller_address

call puts

mov si, 13                                                          ;打印回车

call putc

mov si, 10                                                          ;打印换行

call putc

call say_hello                                            ;打印信息

jmp $

caller_message        db 'Now: I am the caller, address is 0x'

caller_address        dq 0

hello_message         db 13, 10, 'hello,world!', 13,10

db 'This is my first assembly program...', 13, 10, 13, 10, 0

callee_message        db "Now: I'm callee - say_hello(), address is 0x"

callee_address        dq 0

实际上这段汇编语言相当于下面的几条C语言语句。

int main()

{

printf("Now: I am the caller, address is 0x%x",

get_hex_string(current_eip));

printf("\n");

say_hell0();                /* 调用 say_hello() */

}

相比而言,汇编语言的代码量就大得多了。下面是say_hello()的汇编代码。

代码清单2-2(topic02\ex2-1\setup.asm):

;-------------------------------------------

; say_hello()

;-------------------------------------------

say_hello:

mov si, hello_message

call puts

mov si, callee_message

call puts

mov si, say_hello

mov di, callee_address

call get_hex_string

mov si, callee_address

call puts

ret

这个 say_hello()也仅相当于以下几条C语句。

void say_hello()

{

printf("hello,world\nThis is my first assembly program...");

printf("Now: I'm callee - say_hello(), address is 0x%x",

get_hex_string(say_hello));

}

代码清单2-1和2-2就组成了我们这个16位实模式下的汇编语言版本的hello world程序,它在VMware上的运行结果如下所示。

当然仅这两段汇编代码还远远不能达到上面的运行结果,这个例子中背后还有 boot.asm和lib16.asm的支持,boot.asm用来启动机器的MBR模块,lib16.asm则是16位实模式下的库(在lib\目录下),提供类似于C库的功能。

main()的代码被加载到内存0x8000中,lib16.asm的代码被加载到 0x8a00中,作为一个共享库的形式存在。这个例子里的全部代码都在topic02\ex2-1\目录下,包括boot.asm源文件和setup.asm源文件,而lib16.asm则在x86\source\lib\目录下。main()所在的模块是 setup.asm。

16位?32位?还是64位?

在机器启动时处理器工作于16位实模式。这个hello world程序工作于16位实模式下,在编写代码时,需要给nasm指示为16位的代码编译,在代码的开头使用bits 16指示字声明。

bits 32指示编译为32位代码,bits 64指示编译为64位代码。

本文节选自《x86x64体系探索及编程》

电子工业出版社出版

邓志著

x86/x64编程基础相关推荐

  1. X86/X64汇编语言基础

    目录 一.基础介绍 汇编语言简介 80×86 计算机组织 80×86 的指令系统和寻址方式 汇编语言程序格式 汇编语言程序的运行 子程序结构 二.汇编实验 打印输出"Hello World! ...

  2. Intel x86/x64 编程手册-开发文档

    在官网下述地址可以下载: Technical Library 查找以下标题: Intel® 64 and IA-32 Architectures Software Developer's Manual ...

  3. 《x86/x64体系探索及编程》图书信息

    x86/x64体系探索及编程 (对x86处理器介绍得最详尽又最具实践指导意义的一本书) 邓志著 ISBN 978-7-121-18176-4 2012年10月出版 定价:119.00元 16开 840 ...

  4. VC++游戏编程基础无法找到“d3d9.h”问题

    经反复查阅是缺少Direct X SDK导致的,我用的是VC++6.0,支持Direct X SDK 9.0b及之前的版本,最新版DX SDK(JUNE)VC6驾驭不了...下面是我解决问题的思路(只 ...

  5. 【写博客常用】x86,x64,arm都是什么

    [写博客常用]x86,x64,arm都是什么 指令集架构 指令集 参考文章 指令集架构 指令集架构主要分两大类. 复杂指令集运算(Complex Instruction Set Computing,C ...

  6. 【Python学习教程】Python编程基础

    文章目录 编程语言是什么 编译型语言和解释型语言的区别 编译型语言 1) 可执行程序不能跨平台 2) 源代码不能跨平台 解释型语言 关于 Python 总结 Python是什么,Python简介 Py ...

  7. 视频教程-x86/x64软件逆向分析入门-C/C++

    x86/x64软件逆向分析入门 成都理工大学优秀讲师,教授,二十年开发经验,和十六年一线教学工作经验,发表学术论文十余篇.参与包括863项目等多个国家级科研项目,参与包括微信机器人(WeChaty)等 ...

  8. 第1章 Python编程基础

    第1章 Python编程基础 文章目录 第1章 Python编程基础 前言 一.编译型语言和解释型语言的区别 编译型语言 解释型语言 关于 Python 总结 二.Python是什么 三.Python ...

  9. x86架构中断基础介绍

    BIOS/UEFI基础--x86架构中断基础介绍 说明 本文讲的是Intel的x86架构下的中断. 参考的文档主要是<64-ia-32-architectures-software-develo ...

  10. 实验一 Java编程基础

    面向对象--Java实验报告 实验一:Java基础编程 实验一 Java编程基础 <center> <strong>姓名:</strong> <u>XX ...

最新文章

  1. WeQuant交易策略—简单均线
  2. PyCharm3.0默认快捷键
  3. html 垂直线代码,html – Bootstrap 3水平和垂直分隔线
  4. array python 交集_Python基础(二)——列表和元组
  5. 学生管理系统Java版
  6. Android获取所有Activity
  7. 得到python对象的真实大小
  8. Yii2.0 对数据库 查询的一些简单的操作
  9. 『初识C语言』语法入门详解
  10. 利用Seaborn库进行简单的画图
  11. 微信小程序登录界面 服务器,微信小程序之登录页-------实例
  12. Safari浏览器中 视频倍速播放
  13. 设置代理服务器(谷歌+IE)
  14. 干货 :送你一份使用k近邻算法实现回归的实用指南(附代码、链接)
  15. 服务器的cd驱动器怎么修改盘符,更改dvd驱动器盘符,cd驱动器盘符改
  16. 小机器人显示服务器异常,机器人常见异常报警处理、及日常维护保养。
  17. 物联网行业解决方案之智慧畜牧
  18. Dubbo源码分析(一):概览
  19. PTA-整除光棍(C语言)
  20. <数据库> if 条件语句的使用 SQL26 计算25岁以上和以下的用户数量

热门文章

  1. PyCharm导入selenium的webdirver模块出错
  2. 解决QTableWidget不显示数据的问题
  3. 牛客网编程练习之编程马拉松:发工资
  4. 细说show slave status参数详解(最全)【转】
  5. Server的Transfer和Response的Redirect
  6. Android应用性能优化整体策略
  7. 多线程TCP客户端的设计
  8. lib so 中查找函数
  9. Access导入SQL2005
  10. Ubuntu16.04 + ROS下串口通讯