汇编语言的小程序急!!!

汇编语言的小程序急!!!,第1张

改了后的程序:

DATA SEGMENT

AA1 DB 0C7H,24H

AA2 DB 0ACH,79H

BUF DW 2 DUP(?)

DATA ENDS

DATA SEGMENT

CODE SEGMENT ;代码段说明指令

ASSUME CS:CODE,DS:DATA

START: MOV AX,DATA

MOV DS,AX

LEA SI,AA1

LEA DI,AA2

MOV AL,[SI]

MOV BL,[DI]

CLC;将CF清零,因为下面的运算要用到CF的值

ADD AL,BL

INC SI

INC DI

MOV AH,[SI]

MOV BH,[DI]

ADC AH,BH

LEA DI,BUF

MOV [DI],AX

MOV AX,4C00H ;程序结束退出指令,不能少

INT 21H

CODE ENDS

END START

这程序就是为了实现两个为橡橡字数据的加法,激腊先将两个数的低八位取出相加,梁铅旁得到结果存入AL中,但这时要考虑到可能产生向高位产生进位,所以再进行加法前应该把CF清零,既加一句“CLD”,所以在第二次把两个数的高位取出相加时,要用ADC指令,既带进位加法指令,把低位向高位产生的进位加进去。

带注释的都是你给的程序中漏了的部分

代码+注释承上

.386

.model flat,stdcall 这里我们用stdcall 就是函数参数 压栈的时候从最后一个开始压,和被调用函数负责清栈

option casemap:none区分大小写

includelib msvcrt.lib 这里是引入类库 相当于 #include<stdio.h>了

printf PROTO C:DWORD,:VARARG 这个就是声明一下我们要用的函数头,到时候 汇编程序会自动到msvcrt.lib里面找的了

:VARARG 表后面的参数不确定 因为C就是这样的printf(const char *, ...)

这样的函数要注意 不是被调用函数负责清栈 因为它本身不知道有多少个参数

而是有调用者负责清栈 下面会详细说明

.data

szTextFmt BYTE '%d',0这个是用来类型转换的,跟C的一样,字符用字节类型

a dword 1000 假设

b dword 2000 处理数值都用双字 没段山有int 跟long 的区别

//////////////////////////////////////迹肢///////////////////////////////////////////////////

.code

_test proc A:DWORD,B:DWORD

push ebp

mov ebp,esp

mov eax,dword ptr ss:[ebp+8]

add eax,1

mov edx,dword ptr ss:[ebp+0Ch]

add edx,100

add eax,edx

pop ebp

retn 8

_test endp

_main proc

push dword ptr ds:b 反汇编我们看到的b就不是b了而是一个[*****]数字 dword ptr 就是我们在ds(数据段)把[*****]

开始的一个双字长数值取出来

push dword ptr ds:a 跟她对应的还有 byte ptr ****就是取一个字节出来 比如这样 mov al,byte ptr ds:szTextFmt

就把 % 取出来 而不包括 d

call _test

push eax 假设push eax的地址是×××××

push offset szTextFmt

call printf

add esp,8

ret

_main endp

end _main

////////////////////////////////////////////////////////////// 下面介绍堆栈的变化

首先要明白的是 *** 作堆栈段 ss 只能用握州中 esp或ebp寄存器 其他的寄存器eax ebx edx等都不能够用 而 esp永远指向堆栈栈顶 ebp用来 在堆栈段

里面寻址

push 指令是压栈 ESP=ESP-4

pop 指令是出栈 ESP=ESP+4

我们假设main函数一开始堆栈定是 ESP=400

push dword ptr ds:b ESP-4=396 ->里面的值就是 2000 就是b的数值

push dword ptr ds:a ESP-4=392 ->里面的值就是 1000 就是a的数值

call test ESP-4=388->里面的数值是什么?这个太重要了 就是我们用来找游戏函数的原理所在。

里面的数值就是call test 指令下一条指令的地址->即push eax的地址×××××

到了test函数里面

push ebp ESP-4=384->里面保存了当前ebp的值 而不是把ebp清零

mov ebp,esp 这里ESP=384就没变化了,但是 ebp=esp=384,为什么要这样做呢 因为我们要用ebp到堆栈里面找参数

mov eax,dword ptr ss:[ebp+8] 反汇编是这样的 想想为什么a就是[ebp+8]呢

我们往上看看堆栈里地址392处就保存着a的值 这里ebp=384 加上8正好就是392了

这样就把传递过来的1000拿了出来eax=1000

add eax,1 相当于 a+1了 eax=1001

mov edx,dword ptr ss:[ebp+0Ch]0Ch=12 一样道理这里指向堆栈的地址是384+12=396 就是2000了 edx=2000

add edx,100 相当于 b+100 edx=2100

add eax,edx eax=eax+edx=1001+2100=3101 这里eax已经保存了最终的结果了

因为win32汇编一般用eax返回结果 所以如果最终结果不是在eax里面的话 还要把它放到eax

比如假设我的结果保存在变量nRet里面 最后还是要这样 mov eax,dword ptr nRet

pop ebp ESP=384+4=388 而保存在栈顶384的值 保存到 ebp中 即恢复ebp原来的值

因为一开始我们就把ebp的值压栈了,mov ebp,esp已经改变了ebp的值,这里恢复就是保证了堆栈平衡

retn 8ESP+8->396 这里retn是由系统调用的 我们不用管 系统会自动把EIP指针指向 原来的call的下一条指令

由于是系统自动恢复了call那里的压栈所以 真正返回到的时候ESP+4就是恢复了call压栈的堆栈

到了这个时候 ESP=400 就是函数调用开始的堆栈,就是说函数调用前跟函数调用后的堆栈是一样的

这就是堆栈平衡

由于我们用stdcall上面retn 8就是被调用者负责恢复堆栈的意思了,函数test是被调用者,所以负责把堆栈加8,call 那里是系统自动恢复的

push eaxESP-4=396->里面保存了eax的值3101

上面已经看到了eax保存着返回值,我们要把它传给printf也是通过堆栈传递

push offset szTextFmt ESP-4=392->里面保存了szTextFmt的地址 也就是C里面的指针 实际上没有什么把字符串传递的,我们传的都是地址

无论是在汇编或C 所以在汇编里没有什么字符串类型 用最多的就是DWORD。嘿嘿游戏里面传递参数 简单多了

call printf ESP-4=388->里面保存了下一条指令的地址

add esp,8 ESP+8=400 恢复了调用printf前的堆栈状态

上面说了由于printf后面参数是:VARARG 这样的类型是有调用者恢复堆栈的 所以printf里面没有retn 8之类的指令

这是由调用者负责清栈 main是调用者 所以下面一句就是 add esp,8 把堆栈恢复到调用printf之前

而call printf那里的压栈 是由系统做的 恢复的工作也是系统完成 我们不用理 只是知道里面保存是返回地址就够

ret main 函数返回 其他的事情是系统自动搞定 我们不用理 任务完成

我给你个辩野输入三个数,从小到大输出的:

汇编:

inkeymacro nn

mov ah,1h

int 21h

sub al,30h

mov bl,nn

mul bl

add sum,ax

endm

data segment

sum dw 0

str1 dw 0

str2 dw 0

str3 dw 0

buff1db 0

bu2 db " 1 2 3 4 5 6 7 8 9 A", 0dh,0ah,"或斗$"

data ends

stacksegment para stack

db 100 dup(?)

stackends

code segment

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

sub1 proc far

start: push ds

mov ax,0

push ax

mov ax,data

mov ds,ax

mov es,ax

inkey 100 输入第一个数

inkey 10

inkey 1

mov ax,sum

mov str1,ax

mov sum,0

mov dl,"衫灶磨 "

mov ah,2h

int 21h

inkey 100 输入第二个数

inkey 10

inkey 1

mov ax,sum

mov str2,ax

mov sum,0

mov dl," "

mov ah,2h

int 21h

inkey 100 输入第三个数

inkey 10

inkey 1

mov ax,sum

mov str3,ax

mov dl,0dh

mov ah,2h

int 21h

mov dl,0ah

mov ah,2h

int 21h

mov ax,str1 三个数比较大小

cmp ax,str2

jae a7

jmp a8

a7: mov bx,str2

mov str2,ax

mov str1,bx

a8: mov ax,str2

cmp ax,str3

jae a9

jmp a11

a9: mov bx,str3

mov str3,ax

mov str2,bx

mov ax,str1

cmp ax,str2

jae a10

jmp a11

a10: mov bx,str2

mov str2,ax

mov str1,bx

a11: mov ax,str1

mov al,ah

call sub3

mov ax,str1

call sub3

mov dl,"H"

mov ah,2h

int 21h

mov dl," "

mov ah,2h

int 21h

xor ah,ah

mov ax,str2

mov al,ah

call sub3

mov ax,str2

call sub3

mov dl,"H"

mov ah,2h

int 21h

mov dl," "

mov ah,2h

int 21h

xor ah,ah

mov ax,str3

mov al,ah

call sub3

mov ax,str3

call sub3

mov dl,"H"

mov ah,2h

int 21h

ret

sub1 endp

SUB2 PROC

cmp al,9

ja g1

add al,"0"

jmp g2

g1: add al,37h

g2: mov dl,al

mov ah,2

int 21h

RET

SUB2 ENDP

SUB3 PROC

mov buff1,al

shr al,1

shr al,1

shr al,1

shr al,1

CALL SUB2

mov al,buff1

and al,0fh

CALL SUB2

RET

SUB3 ENDP

code ends

end start

高级(C语言):

#include<stdio.h>

void main()

{

int t

int a,b,c

printf("请输入三个整数:\n")

scanf("%d%d%d",&a,&b,&c)

if(a>b)

{

t=a

a=b

b=t

}//a,b交换

if(a>c)

{

t=a

a=c

c=t

}//a,c交换

if(b>c)

{

t=b

b=c

c=t

}//b,c交换

printf("从小到大输出:%d,%d,%d\n",a,b,c)

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12564258.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-26
下一篇 2023-05-26

发表评论

登录后才能评论

评论列表(0条)

保存