学习windows32汇编编程(笔记)

    今天想学习win32汇编编程,在taowen博客中阅读了其翻译的Win32Asm教程,摘抄了一些我自己需要学习的要点。原教程的博客地址是:http://www.cnblogs.com/taowen/articles/11237.html  。很高兴网上有这么多爱学习的朋友们奉献资料。

    在Windows中编程,你不再需要了解Dos中断(interrupt)和端口(port)In/Out函数。在Windows中,WindowsAPI提供了你可在你的程序中使用的标准函数
     需要参考一些API函数的用法,现在有极好的MSDN供选择
     eax (ax/ah/al) 加法器
     ebx (bx/bh/bl) 基(base)
     ecx (cx/ch/cl) 计数器
     edx (dx/dh/dl) 数据
     段寄存器定义了哪一段内存被使用。你可能在win32asm中用不着它们,因为windows有一个平坦(flat)的内存系统。在windows中,段有4GB的大小,所以你在Windows中不需要段。段总是16位寄存器。
     CS  代码段
     DS  数据段
     SS  栈段
     ES  扩展段
     FS (only 286+)  全功能段
     GS (only 386+)  全功能段
     你可以把指针寄存器当作全功能寄存器来使用(除了eip),只要你保存并恢复它们的原始值。指针寄存器之所以这么叫是因为它们经常被用来存储内存地址。一些伪代码(movb,scasb等)也要用它们。
     esi (si)  源索引
     edi (di)  目标索引
     eip (ip)  指令指针
     2个栈寄存器:esp和ebp。esp装有内存中当前栈的位置。Ebp在函数中被用成指向局部变量的指针。
     在运行于Dos和Win3.xx的16位程序中,内存被分成许多个段。这些段的大小为64kb。最多有65536个段。为了指向段中的位置,需要使用offset。一个offset是段内部的一个位置。每个段最多有65536个offset。在32位Windows(95及以上),你仍然有段,但不用管他们了。因为它们不再是64kb,而是4GB。你如果尝试着改变段寄存器中的一个,windows甚至会崩溃。这称为平坦(flat)内存模式。只有offset,而且是32位的,因而范围从0到4,294,967,295。内存中的每一个地址都是用offset表示的。
     32位的值也就是4字节大小。
     十六进制dword(32位)值放在内存中时是这样:40, 30, 20, 10(每个值占一个字节(8位))
     十六进制word(16位)值放在内存中时是这样:50, 40
     mov cl, byte ptr [34h] ; cl得到值0Dh(参考上表)
     mov dx, word ptr [3Eh] ; dx将得到值 7DEFh (记住反序), 因为存储在内存中的值使用了little endian格式。这意味着越靠右的字节位数越高:字节顺序被反转了
     大小有时不是必须的。
     Mov eax,[00403045h]
     因为eax是32位寄存器,编译器假定(也只能这么做)它应该从地址403045(十六进制)取个32位的值。
     可以直接使用数值:
     mov edx, 5006
     这只是使得edx寄存器装有值5006,综括号[和]用来从括号间的内存地址处取值,没有括号就只是这个值。寄存器和内存地址也可以(他应该是32位程序中的32位寄存器):
     mov eax,403045h;使eax装有值403045h(十六进制)
     mov cx,[eax];把位于内存地址eax的word大小的值(403045)移入cx寄存器。
     在mov cx, [eax]中,处理器会先查看eax装有什么值(=内存地址),然后在那个内存地址中有什么值,并把这个word(16位,因为目标-cx-是个16位寄存器)移入cx。
     汇编源文件被分成了几个部分。这些部分是code,data,未初始化data,constants,resource和relocations,资源部分是资源文件创建的。
     在你的源文件(*.asm)中,你可以用部分标识符定义各部分:

     .code;代码部分由此开始
     .data;数据部分由此开始
     .data?;未初始化数据部分由此开始
     .const;常量部分由此开始

    可执行文件(*.exe,*.dll和其他)是(在win32中)可移植执行格式(PE)。部分(Sections)的一些属性定义在PE头中:
    Section名,RVA,offset,原始大小,虚拟大小和标志。Rva(相对虚拟地址)是将要装入的section部分的相对内存地址。这里相对的意思是相对于程序载入的基地址。这个地址也在PE头中,但可以由PE-loader改变(使用relocation部分)。Offset是初始化数据所在的exe文件本身的原始offset。虚拟大小是程序在内存中将达到的大小。标志是读/写/可执行等。
你和处理器都不能看出一个值是signed还是unsigned。好消息是对于加法和减法来说,一个数是signed还是unsigned没有关系。

    计算:-4+9

    FFFFFFFC+00000009=00000005(这是对的)

    计算:5-(-9)

    00000005-FFFFFFF7=0000000E(这也是对的,5――9=4)

    坏消息是对于乘法,除法和比较(compare)并不是这样。因此,对于signed数有特殊的乘除伪代码:imul和idiv

    Imul也有一个比mul好的地方在于它可以接受直接数值:

    imul src
    imul src, immed
    imul dest,src, 8-bit immed
    imul dest,src

    idiv src

    它们几乎和mul,div一样,只是它们可以计算signed值。比较(compare)可以和unsigned一样用。但标志作不同的设置。因此,对于符号和无符号数字有不同的jump指令:

    cmp ax, bx
    ja somewhere

    ja是一个无符号跳转指令。如果大于就跳转。考虑这个ax=FFFFh(无符号时为FFFFh,有符号时为-1)和bx=0005h(无符号时为5,有符号时为5)。由于FFFFh在无符号时比0005大,ja指令会跳转,但如果用的是jg(指一个有符号跳转):

    cmp ax, bx
    jg somewhere

    jg指令不会跳转,因为-1不比5大。

    只要记住这点:一个数字是有符号还是无符号取决于你怎样对待这个数。
    Test对两个参数(目标,源)执行AND逻辑操作,并根据结果设置标志寄存器。结果本身不会保存。Test用来测试一个位,例如寄存器:

    test eax, 100b;b后缀意为二进制
    jnz bitset

    如果eax右数第三个位被设置了,jnz将会跳转。Test的一个非常普遍的用法是用来测试一方寄存器是否为空:

    test ecx, ecx
    jz somewhere
    如果ecx为零,Jz跳转

    栈是内存的一个地方,esp为指向栈的指针。栈是用来保存临时数值的地方,有两个指令来放入一个指和再把它取出来:push和pop。Push把一个指压入栈。Pop再把它弹出来。最后一个放入的值最先出来。一个值被放入栈中,栈指针步减,当它移出来的时候,栈指针步增。栈顶总是栈中地址最小的位置
    Call跳转到某段代码而且一发现RET指令就返回。你可以把它们看成在其他编程语言中的函数或子程序。call把EIP(指向将要执行指令的指针)压入栈,而ret指令在它返回的时候把它弹出来。你也可以给一个call指定的参数。这是由压栈来完成的:
    push something
    push something2
    call procedure

    在一个调用的内部,参数从栈中读出并使用。注意,只在过程中需要的局部变量也储存在栈中。只要记住你可以写过程,而且它们可以由参数。一个重要的地方:
    eax几乎总是用来装一个过程的返回值。
    对于windows函数也是如此。但然,你可以在你的过程使用其他的寄存器,但这是标准。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值