`

x86/x64编程基础

阅读更多

选择编译器

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

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

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

masm是微软发布的汇编编译器,现在已经停止单独发布,被融合在Visual Studio产品中。gasLinux平台上的免费开源汇编编译器,使用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在机器语言中应该怎样表达?

这是一个很麻烦的过程,abc都是变量,在机器语言中应该怎样表达?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可能是外部变量

变量ab是在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是地址值0x0040801clittle-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-2topic02\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-12-2就组成了我们这个16位实模式下的汇编语言版本的hello world程序,它在VMware上的运行结果如下所示。

 

当然仅这两段汇编代码还远远不能达到上面的运行结果,这个例子中背后还有 boot.asmlib16.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体系探索及编程part1

    11 1.2.4 unsupported 编码值 14 1.2.5 浮点数精度的转换 15 1.2.6 浮点数的溢出 17 1.2.7 BCD 码 20 1.2.8 SIMD 数据 21 第2 章 x86/x64 编程基础 23 2.1 选择编译器 23 2.2 机器语言 24 2.3 Hello world 25 2.3.1...

    x86/x64体系探索及编程

    x86/x64体系探索及编程(带书签):本书是对Intel手册所述处理器架构的探索和论证。全书共五大部分,从多个方面对处理器架构相关的知识进行了梳理介绍。书中每个章节都有相应的测试实验,所运行的实验例子都可以在真实...

    x86 x64体系探索及编程part4

    11 1.2.4 unsupported 编码值 14 1.2.5 浮点数精度的转换 15 1.2.6 浮点数的溢出 17 1.2.7 BCD 码 20 1.2.8 SIMD 数据 21 第2 章 x86/x64 编程基础 23 2.1 选择编译器 23 2.2 机器语言 24 2.3 Hello world 25 2.3.1...

    x86 x64体系探索及编程part3

    11 1.2.4 unsupported 编码值 14 1.2.5 浮点数精度的转换 15 1.2.6 浮点数的溢出 17 1.2.7 BCD 码 20 1.2.8 SIMD 数据 21 第2 章 x86/x64 编程基础 23 2.1 选择编译器 23 2.2 机器语言 24 2.3 Hello world 25 2.3.1...

    x86 x64体系探索及编程 part2

    11 1.2.4 unsupported 编码值 14 1.2.5 浮点数精度的转换 15 1.2.6 浮点数的溢出 17 1.2.7 BCD 码 20 1.2.8 SIMD 数据 21 第2 章 x86/x64 编程基础 23 2.1 选择编译器 23 2.2 机器语言 24 2.3 Hello world 25 2.3.1...

    x86_x64体系探索及编程

    本书是对Intel手册所述处理器架构的探索和论证。全书共五大部分,从多个方面对处理器架构相关的知识进行了梳理介绍。...本书适合有一定的x86基础知识,且对了解处理器架构及编程感兴趣的读者阅读。

    Python v3.7.3 官方最新版【x86x64.rar

    语言:英文 ...它带有一大批标准模块可以作为你自己的程序的基础——或作为学习Python编程的例子。系统还提供了关于文件输入输出、系统调用、插座(sockets)的东西,甚至提供了窗口系统(STDWIN)的通用接口。

    java源码期编译器运行时-mql4-lib:面向专业开发人员的MQL4/5基础库

    x86/x64)的真正跨版本库。 也许该库将来会更名为 mql-lib。 安装 只需将库复制到您的 MetaTrader 数据文件夹的Include目录,使用您选择的根目录名称,例如: 对于 MT4: <MetaTrader>\MQL4\Include\Mql\<mql4-...

    jre-7u17-windows-x64.exe

    JDK是一个开发环境,用于构建应用程序,applet程序,和使用Java编程语言的组成部分。 Java Development Kit(JDK)是Sun Microsystems针对Java开发员的产品。自从Java推出以来,JDK已经成为使用最广泛的Java SDK。JDK ...

    编程高手箴言(推荐)

    1.3.1 规范的格式是入门的基础 13 1.3.2 调试的重要性 17 1.4 开放性思维 18 1.4.1 动态库的重要性 19 1.4.2 程序设计流程 20 1.4.3 保证程序可预测性 21 第2章 认识CPU 23 2.1 8位微处理器回顾 23 2.2 16位微处理器...

    精通qt4编程(源代码)

    自Trolltech公司1996年推出Qt 1.0版以来,Qt已经从2.x,3.x发展到了现在的Qt 4.3,本书就是基于最新的Qt 4.3写成。因为Qt 4框架设计得非常优秀,在2006年的第16届Jolt大奖上,Qt 4获得了类库、框架和组件类别的Jolt...

    新版Android开发教程.rar

    ----------------------------------- Android 编程基础 1 封面----------------------------------- Android 编程基础 2 开放手机联盟 --Open --Open --Open --Open Handset Handset Handset Handset Alliance ...

    rustykext:部分用Rust编程语言编写的OS X kext

    RustyKext 当前非常少的OS X内核扩展,部分用Rust编程语言编写。 加载kext时,将“Rust的hello”写入内核日志。 就是这样。 Xcode项目假定rustc安装在/usr/local/bin/rustc 。 使用标记为“不稳定”的各种功能,因此...

    优化C++软件:Windows、Linux、DNC的优化指南

    本手册适用于那些想要使软件...x86 处理器是 Widows,Linux, BSD 和 Mac OS X 中最常用的平台,即使 这些操作系统也适用于其他微处理器,当然很多设备也使用其他平台和变异语言。本手册是一个系列五本手册中的第一本:

    精通Qt4编程(第二版)源代码

    自Trolltech公司1996年推出Qt 1.0版以来,Qt已经从2.x,3.x发展到了现在的Qt 4.3,本书就是基于最新的Qt 4.3写成。因为Qt 4框架设计得非常优秀,在2006年的第16届Jolt大奖上,Qt 4获得了类库、框架和组件类别的Jolt...

    xr21v1414 USB驱动源码,支持5.15版本内核

    在官方xr21v1414 USB驱动源码基础上进行修改,支持5.15版本内核。由于5.15版本内核修改了部分tty相关接口,导致官方驱动无法正常编译,因此需要进行修改适配。本源码支持3.6以上内核,在树莓派 2022-04-04-raspios-...

    [源码恢复反汇编静态分析工具IDA.pro.5.5]idapro55.part1

    它支持数十种CPU指令集其中包括Intel x86,x64,MIPS,PowerPC,ARM,Z80,68000k,c8051等等。它的优点是可以更好的反汇编和更有深层分析。可以快速到达指定的代码位置;可以看到跳到指定的位置的jmp的命令位置;可以看...

    《Linux 系统及网络应用》(电子版讲义 第三版)

    它具有良好的开放性,可以运行在 Intel X86、Alpha、PowerPC、Mips 及 Sparc等多种硬件平台上。作 为一个类UNIX的操作系统,L inux完全符合POSIX 1003.1 标准。Linux 在实现技术上支持多用户访问和多任务编程,采用...

    软件定义的网络与安全方案.pptx

    运维排障 安全策略跟随虚拟机移动 虚拟机的可视化管理 命令行或GUI界面无法自动化部署 Floor-1: VLAN1 – 10.x.x.x Floor-2: VLAN2 – 172.16.x.x 软件定义的网络与安全方案全文共39页,当前为第11页。 通用X86...

    编程高手箴言(中文完整版)(13M)

    1.3.1 规范的格式是入门的基础 13 1.3.2 调试的重要性 17 1.4 开放性思维 18 1.4.1 动态库的重要性 19 1.4.2 程序设计流程 20 1.4.3 保证程序可预测性 21 第2章 认识CPU 23 2.1 8位微处理器回顾 23 2.2 16位微处理器...

Global site tag (gtag.js) - Google Analytics