`

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体系探索及编程(邓志)高清最新版

    《x86_x64体系探索及编程》是由邓志编著的一本深入解析x86和x64架构的书籍。这本书详细介绍了这两种处理器架构的基础知识、工作原理以及编程技术,是理解现代计算机硬件与软件交互的重要参考资料。 在x86体系结构中...

    x86x64体系探索及编程

    《x86x64体系探索及编程》一书深入探讨了x86和x64架构下的计算机...总之,《x86x64体系探索及编程》是一本全面的指南,不仅介绍了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手册所述处理器架构的探索和论证。全书共五大部分,从多个方面对处理器架构相关的知识进行了梳理介绍。书中每个章节都有相应的测试实验,所运行的实验例子都可以在真实...

    x86x64体系探索及编程-DOS版本程序

    《x86/x64 体系探索及编程》是一本深入探讨x86和x64架构的书籍,尤其在DOS环境下进行了实践性的程序设计。邓志老师通过这本书,引领读者了解这两种主流处理器架构的基本原理,以及如何在DOS操作系统下编写程序。 ...

    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...

    directshow开发环境include/lib[x86/x64]

    这个压缩包文件“directshow开发环境include/lib[x86/x64]”显然是为开发者提供DirectShow的开发资源,包括头文件(include)和库文件(lib),分别适用于x86(32位)和x64(64位)平台。 **DirectShow基础知识** ...

    MinGW for win 4.9.1 x86/x64 离线包

    MinGW 4.9.1是该工具集的一个版本,发布于x86和x64架构,意味着它可以支持32位和64位的Windows系统。这个离线包特别适合那些没有稳定网络连接或者希望在无互联网环境中安装MinGW的用户。"解压即用"的特性使得安装...

    dotNetFx40LP_Full_x86_x64zh-Hans、dotNetFx45LP_Full_x86_x64zh-Hans

    标题中的"dotNetFx40LP_Full_x86_x64zh-Hans"和"dotNetFx45LP_Full_x86_x64zh-Hans"是两个与Microsoft .NET Framework相关的安装程序,分别对应.NET Framework 4和.NET Framework 4.5的中文语言包(zh-Hans表示简体...

    dotnetfx45_full_x86_x64.zip

    标题“dotnetfx45_full_x86_x64.zip”指的是.NET Framework 4.5的完整安装包,适用于32位(x86)和64位(x64)操作系统。.NET Framework是由微软开发的一个软件框架,它为Windows应用程序提供了运行环境和支持。这个...

    NET Framework 4.0 离线安装包_x86_x64

    标题中的“_x86_x64”表明这个安装包包含了适用于32位(x86)和64位(x64)系统的版本,因此无论你的计算机架构如何,都能找到合适的版本进行安装。 .NET Framework 4.0引入了许多新特性,包括: 1. **改进的性能*...

    sublime text 3 安装及ctags安装包 win7/xp(x86/x64)

    在本文中,我们将详细探讨如何在Windows 7或XP系统(无论是x86还是x64架构)上安装Sublime Text 3,并安装`ctags`插件,这将极大地提升代码导航和搜索功能。 首先,让我们了解Sublime Text 3的基础安装步骤: 1. *...

    .net4.5离线安装包_x86_x64

    这个离线安装包`.net4.5离线安装包_x86_x64`包含了针对32位(x86)和64位(x64)系统的安装程序,适用于Windows 7 64位操作系统。离线安装包意味着用户可以在没有互联网连接的情况下进行安装,这对于网络环境不稳定...

    dotNetFx40_Full_x86_x64.zip

    标题中的"dotNetFx40_Full_x86_x64.zip"是一个.NET Framework 4.0完整版的压缩包,适用于32位(x86)和64位(x64)操作系统。这个文件通常被用来在计算机上安装微软的.NET Framework 4.0框架,它是开发和运行基于...

    NDP461-KB3102436-x86-x64-AllOS-ENU.zip

    标题中的"NDP461-KB3102436-x86-x64-AllOS-ENU.zip"指示了这是一个与.NET Framework相关的更新包,具体是.NET Framework 4.6.1的更新。KB3102436是这个更新的唯一标识符,通常用于微软发布的安全补丁或功能更新。...

    dotnetfx40lp_full_x86_x64zh-hans

    标题中的"dotnetfx40lp_full_x86_x64zh-hans"是指微软的.NET Framework 4.0 Language Pack(简体中文版),这是一个关键的软件开发平台,用于构建和运行使用C#、VB.NET、F#等语言编写的Windows应用程序。"x86_x64...

    dotNetFx40LP_Client_x86_x64zh-Hans

    "dotNetFx40_Client_x86_x64.exe"是.NET Framework 4.0的基础客户端版本,包含了运行.NET Framework 4.0应用程序所需的核心组件。此版本针对那些不需要完整.NET Framework功能集的桌面应用,旨在减少安装大小和提高...

    NET Framework 3.5 离线安装包_x86_x64

    描述中提到".net3.5离线安装包_x86_x64在7 64位离线安装可以使用",这意味着该安装包特别适用于运行Windows 7 64位操作系统的机器。在Windows 7或更高版本的系统中,.NET Framework 3.5并不是默认预装的,因此用户...

Global site tag (gtag.js) - Google Analytics