c语言如何实现8位指针指向32位数据,《汇编语言》王爽版 Nisy学习笔记(精辟的第十一章总结完毕)...

第六章 逻辑思维的扩展

程序由一个段扩展为多个段的历程,整个演变过程被王老师推理的非常经典。

**************************************************************************************

第七章 利用基地址和偏移地址 实现对数据、数据的处理

我们要设计一个转化大小写的程序,首先要弄明白转化的算法,我们用 AND 0DFH 来实现小变大,用 OR 20H 来实现大变小。

第二个问题要解决如何传参的问题,我们用C来看一下:引用:

/**************************************************************************/

#include

using namespace std;

void change(char *s,int n,int t)

{

int i;  /* 查看该局部变量在堆栈的位置 */

for(i=0;i

{

if(t==0)

{

if( *(s+i) >= 'a' && *(s+i) <= 'z'  )

*(s+i)&=0x0df;

}

if(t==1)

{

if( *(s+i) >= 'A' && *(s+i) <= 'Z'  )

*(s+i)^=0x20;

}

}

}

void main()

{

char s[]="Hello,Nisy!";

puts(s);

change(s,strlen(s),0);

puts(s);

change(s,strlen(s),1);

puts(s);

}

/**************************************************************************/运行结果:

Hello,Nisy!

HELLO,NISY!

hello,nisy!

先OD一下 看下参数和局部变量在堆栈中的位置:

00401150  /> \55            PUSH EBP

00401151  |.  8BEC          MOV EBP,ESP

00401153  |.  83EC 44       SUB ESP,44         // SUB 的数值小一些也是OK的

00401156  |.  53            PUSH EBX           // 将用到的 寄存器 压栈

00401157  |.  56            PUSH ESI

00401158  |.  57            PUSH EDI

00401159  |.  C745 FC 00000>MOV DWORD PTR SS:[EBP-4],0       //  局部变量 i=0

00401160  |.  EB 09         JMP SHORT std.0040116B

堆栈数据:

0012FF10   00000000    .. 这里是 局部变量 i

0012FF14  /0012FF80    .. 这里是 PUSH EBP

0012FF18  |00401257  返回到 std.00401257 来自 std.00401005

0012FF1C  |0012FF74  ASCII "Hello,Nisy!"

0012FF20  |0000000B

0012FF24  |00000000

用IDA加载 看下 change 函数是如何编写的:

/**************************************************************************/

.text:00401150 change          proc near               ; CODE XREF: j_changej

.text:00401150

.text:00401150 var_4_i         = dword ptr -4

.text:00401150 arg_0_s         = dword ptr  8

.text:00401150 arg_4_len       = dword ptr  0Ch

.text:00401150 arg_8_t         = dword ptr  10h

.text:00401150

.text:00401150                 push    ebp             ; var_型 为局部变量 4为相对与 ESP+N 的N

.text:00401151                 mov     ebp, esp        ; arg_型 为参数 0 4 8 分别 + 8 为该参数在堆栈中的位置

.text:00401153                 sub     esp, 44h        ; 此为参数从左到右的顺序 (Std模式 参数从右到左压栈)

.text:00401156                 push    ebx

.text:00401157                 push    esi

.text:00401158                 push    edi

.text:00401159                 mov     [ebp+var_4_i], 0 ; 局部变量 i 赋初值 0

.text:00401160                 jmp     short loc_40116B

.text:00401162 ; ---------------------------------------------------------------------------

.text:00401162

.text:00401162 loc_401162:                             ; CODE XREF: change:loc_4011DDj

.text:00401162                 mov     eax, [ebp+var_4_i]

.text:00401165                 add     eax, 1

.text:00401168                 mov     [ebp+var_4_i], eax

.text:0040116B

.text:0040116B loc_40116B:                             ; CODE XREF: change+10j

.text:0040116B                 mov     ecx, [ebp+var_4_i]

.text:0040116E                 cmp     ecx, [ebp+arg_4_len]

.text:00401171                 jge     short loc_4011DF

.text:00401173                 cmp     [ebp+arg_8_t], 0 ; 判断是哪种转化方式 0 为大写转小写

.text:00401177                 jnz     short loc_4011A8

.text:00401179                 mov     edx, [ebp+arg_0_s] ; edx 做字符串的基地址

.text:0040117C                 add     edx, [ebp+var_4_i] ; 计算第 i 位字符的地址

.text:0040117F                 movsx   eax, byte ptr [edx]

.text:00401182                 cmp     eax, 61h        ; 以下为判断 字符是否在 'A'和'Z'之间

.text:00401185                 jl      short loc_4011A8

.text:00401187                 mov     ecx, [ebp+arg_0_s]

.text:0040118A                 add     ecx, [ebp+var_4_i]

.text:0040118D                 movsx   edx, byte ptr [ecx]

.text:00401190                 cmp     edx, 7Ah

.text:00401193                 jg      short loc_4011A8 ; 以上为判断 字符是否在 'A'和'Z'之间

.text:00401195                 mov     eax, [ebp+arg_0_s]

.text:00401198                 add     eax, [ebp+var_4_i]

.text:0040119B                 mov     cl, [eax]

.text:0040119D                 and     cl, 0DFh

.text:004011A0                 mov     edx, [ebp+arg_0_s]

.text:004011A3                 add     edx, [ebp+var_4_i]

.text:004011A6                 mov     [edx], cl       ; 转化后 实现 寄存器 ==> 内存数据 的传递

.text:004011A8

.text:004011A8 loc_4011A8:                             ; CODE XREF: change+27j

.text:004011A8                                         ; change+35j ...

.text:004011A8                 cmp     [ebp+arg_8_t], 1

.text:004011AC                 jnz     short loc_4011DD

.text:004011AE                 mov     eax, [ebp+arg_0_s]

.text:004011B1                 add     eax, [ebp+var_4_i]

.text:004011B4                 movsx   ecx, byte ptr [eax]

.text:004011B7                 cmp     ecx, 41h

.text:004011BA                 jl      short loc_4011DD

.text:004011BC                 mov     edx, [ebp+arg_0_s]

.text:004011BF                 add     edx, [ebp+var_4_i]

.text:004011C2                 movsx   eax, byte ptr [edx]

.text:004011C5                 cmp     eax, 5Ah

.text:004011C8                 jg      short loc_4011DD

.text:004011CA                 mov     ecx, [ebp+arg_0_s]

.text:004011CD                 add     ecx, [ebp+var_4_i]

.text:004011D0                 mov     dl, [ecx]

.text:004011D2                 xor     dl, 20h

.text:004011D5                 mov     eax, [ebp+arg_0_s]

.text:004011D8                 add     eax, [ebp+var_4_i]

.text:004011DB                 mov     [eax], dl

.text:004011DD

.text:004011DD loc_4011DD:                             ; CODE XREF: change+5Cj

.text:004011DD                                         ; change+6Aj ...

.text:004011DD                 jmp     short loc_401162

.text:004011DF ; ---------------------------------------------------------------------------

.text:004011DF

.text:004011DF loc_4011DF:                             ; CODE XREF: change+21j

.text:004011DF                 pop     edi

.text:004011E0                 pop     esi

.text:004011E1                 pop     ebx

.text:004011E2                 mov     esp, ebp

.text:004011E4                 pop     ebp

.text:004011E5                 retn

.text:004011E5 change          endp

/*******************************************************************/

怎么C的代码编译出来 执行上这么费劲呢 汗一个 ~~ 摸清规律后,我们开始行动 ~~引用:

assume cs:code,ds:data,ss:stack

stack segment

dd 20 dup (?)

stack ends

data segment

szTest db 'hello,Nisy!',0

data ends

code segment

; 构造一个将小写字母转化为大写的函数

ChangeSmallToBig:

push bp

mov bp,sp

sub sp,10

push cx

push bx

push dx

push si

mov bx,[bp+4+0]           ; 0 s

mov cx,[bp+4+2]           ; 4 size

cmp word ptr [bp+4+4] ,0

jnz small

mov si,0

big:

mov dl,byte ptr [bx+si]

cmp dl,'a'

jl big_1

cmp dl,'z'

jg big_1

and dl,0dfh

mov byte ptr [bx+si],dl

big_1:

inc si

loop big

jmp over

small:

cmp word ptr [bp+4+4] ,1   ; samm 的时候用一下i 呵呵

jnz over

mov word ptr [bp-2],0

mov si,word ptr [bp-2]    ; -4 i

small_1:

mov si,word ptr [bp-2]

mov dl,byte ptr [bx+si]

cmp dl,'A'

jl small_2

cmp dl,'Z'

jg small_2

or dl,020h

mov byte ptr [bx+si],dl

small_2:

inc si

mov word ptr [bp-2],si

loop small_1

over:

pop si

pop dx

pop bx

pop cx

mov sp,bp

pop bp

ret

; 函数结束

start:

mov ax,stack

mov ss,ax

mov sp,4*20

mov ax,data

mov ds,ax

mov bx,offset szTest

mov cx,11

xor ax,ax

push ax

push cx

push bx

call ChangeSmallToBig

mov bx,offset szTest

mov cx,11

mov ax,1

push ax

push cx

push bx

call ChangeSmallToBig

mov ax,4c00h

int 21h

code ends

end start**************************************************************************************引用:

查看程序的运行结果方法:

输入:

debug test.exe

u

g 7b

d ds:0

u

g 8a

d ds:0就可以看到内存中,字符串大小写的转化了。

代码上其实还差一个 ShowText 的函数,回头在写,先来总结下对以上这段代码的思考

1. 首先是太刻意模仿 C 了,为什么要 sub sp,10 其实真的没必要,直接 push 0 不就算定义了一个变量么,回头再用 [ebp-2] 就可以操作了。

2. 对于小的函数,其实无需必要搞 push ebp mov ebp,esp 这样正式的函数入口。计数器完全可以用寄存器替代。

3. 在汇编中,犯下了一个错误,其实汇编语言中是没有 for() 语句的,for 用 while 给替代了,我们通过看 WIN32的汇编,和IDA对程序的反编译就可以了解到。

下面我们定义一个数组  char a[10];

在处理该数组的时候,我们习惯上用一个循环

#include

main()

{

char a[10];

int i;

for(i=0;i<10;i++)

{

*(a+i)=getchar();

}

*(a+9)='\0';

puts(a);

}

我们处理的时候,用一个首地址+偏移值来做处理。

在汇编中我们照样可以构建指针来实现对数组的操作。可以使用寄存器组合来构建,比如[bx+idata],为了更为方便的处理数据,我们又引入了两个寄存器,SI 和 DI (这两个寄存器不可拆分为两个 8 位单元使用),他们的功能和 bx 类似(段地址都默认放在 DS 中)。这样我们就可以构建强大的数组指针。组合格式如:

[BX + IDATA]

[SI + IDATA]

[DI + IDATA]

[BX + SI]

[BX + DI]

[BX + SI + IDATA]

[BX + DI + IDATA]

说明的是,WIN16下只有这三个 通用寄存器 来做指针来处理,而WIN32下是都可以使用的,比如[EAX]。

下边我们看一下本章的问题 7.9 引用:

;*****************************************************************

assume cs:code,ss:stack,ds:data

stack segment

dd 20 dup (?)

stack ends

data segment

db '1. hello        '

db '2. china        '

db '3. nisy         '

db '4. good         '

data ends

code segment

start:

mov ax,stack

mov ss,ax

mov sp,20*4

mov ax,data

mov ds,ax

mov bx,0

mov cx,4

str_0:

push cx

mov si,0

mov cx,4

str_1:

mov dl,byte ptr [bx+si+3]

and dl,11011111b            ; 偷个懒 对数据不做判断了

mov byte ptr [bx+si+3],dl

inc si

loop str_1

add bx,10h

pop cx

loop str_0

mov ax,4c00h

int 21h

code ends

end start

;*****************************************************************PS: 我们处理BX 时,相当于将数据作为二维数组 a[4][16] 处理,bx+16 相当于 *(a+1) ,当然,我们也可以将其视为顺序表数据,循环部分也可以写成这样 BX 只做基址处理,si 做指针处理。

mov bx,0

mov cx,4

str_0:

push cx

mov cx,4

str_1:

mov dl,byte ptr [bx+si+3]

and dl,11011111b            ; 偷个懒 对数据不做判断了

mov byte ptr [bx+si+3],dl

inc si

loop str_1

add si,9

pop cx

loop str_0引用:

这里放一个我写代码和看结果的心得:

记事本保存一段代码 保存到 c:\masm5 目录中(如文件名为 test.asm)

若想检测下自己的代码是否有格式上的错误 直接 cmd --> cd\ --> cd masm5 --> masm 后回车,输入 文件名 让其编辑.

如果OK最好,若有提示问题,直接看该行代码是哪出的错,修改后保存直接运行

masm test;

link test;

当我们修改文件后 按向上的箭头 就可以看到该指令 敲下回车就可以继续编译。

然后是看结果,到现在为止,我们还未解除 0XB8000000 这个地址,所以看结果就需要看内存的数据,我的方法是:

输入 debug test.exe

然后 u 直到看到 mov ax,4c00 这行代码 假如说该代码偏移地址为29 输入 g 29  然后 d ds:0 (假如0是我们字符串在代码段的偏移地址) 就可以看到我们的程序是否正确的处理了字符串。**************************************************************************************

第八章

第八章多半还是寻址,处理二维数组的数据。其中介绍了一个 div 除法指令。

这里引入另一个寄存器,就是 DX 寄存器,到现在为止 我们 8 个通用寄存器就介绍完了。

在进行乘法和除法运算时,我们就需要考虑到计算结果的如何保存的问题。

比如 100 * 100 = 10000 通过该结果我们可得出:2位 * 2位 结果一定不超过 4位。所以做16位数据运算时,16位 * 16位 其结果必定可以用 32 位来表示。 于是退出,我们做计算时,让 DX 和 AX 联合, DX做高16位,AX做低16位,这样就可以计算16位数据的运算。这个就是我们处理 16 位数据的思路。

本章只介绍了除法操作,

被除数若32位,则用DX+AX表示, 商保存再AX中,余数保存再DX中

被除数若16位,则用  AX 表示, 商保存在AL中,余数保存再AH中

当我们将被除数设置好之后,使用div指令即可

div reg

div [内存数据]

注意的是 div 指令后不能是立即数 必须得是寄存器或内存数据

在debug中随意写一些除法运算来观察一下

C:\>debug

-a

0B52:0100 mov ax,10

0B52:0103 mov cx,3

0B52:0106 div cl

0B52:0108

-r

AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000

DS=0B52  ES=0B52  SS=0B52  CS=0B52  IP=0100   NV UP EI PL NZ NA PO NC

0B52:0100 B81000        MOV     AX,0010

-t

AX=0010  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000

DS=0B52  ES=0B52  SS=0B52  CS=0B52  IP=0103   NV UP EI PL NZ NA PO NC

0B52:0103 B90300        MOV     CX,0003

-t

AX=0010  BX=0000  CX=0003  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000

DS=0B52  ES=0B52  SS=0B52  CS=0B52  IP=0106   NV UP EI PL NZ NA PO NC

0B52:0106 F6F1          DIV     CL

-t

AX=0105  BX=0000  CX=0003  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000

DS=0B52  ES=0B52  SS=0B52  CS=0B52  IP=0108   NV UP EI PL NZ AC PO NC

0B52:0108 B81000        MOV     AX,0010

这一章介绍内容不多,最后一个图表题也是对二维数组的考察,比较简单,回头再写。

**************************************************************************************

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值