asm操作数组(转自看雪)

前言:
这个不算是asm魅力系列的文章,只是回答一个朋友的问题!因为写的长了就发出来,希望对大家有帮助!
问题:

http://bbs.pediy.com/showthread.php?p=694325#poststop

任何语言中的数组实际上都是指针的概念,你这样想,一些数据放在内存的一个区域里面,我们要怎么访问他们呢?

步骤:
首先我们得知道这些数据在哪个内存块。其次要知道怎么在这个内存块里面找到我们要的那个指定的数据!

C或者是其他的高级语言把这些东西格式化了,比如char a[]={1,2,3,4};然后访问的时 候 a[0]  a[1]  a[2]   a[3] 实际上还是以前的老话,你要是理解了这种抽象过的符号表示的话,其实是很好理解的。但是asm比较 接近人的思维,什么思维呢?就是我在步骤里提到的这种人人都能立刻想到的思路!

(一)
我先就用masm来说把!那么masm也做了一些格式化,所以我们操作数组也可以比较方便!
来看一小段:

代码:
.data
Array BYTE 1,2,3
.code
Mov esi,OFFSET Array

那么要访问第一个数组元素的话,就是mov eax,[esi],第二个呢就是inc esi , mov eax,[esi]
是和C一样简单的。
关键就是offset,他是干什么呢?就是相当于是把当前的指针指向Array这个内存区域的起始。OK。
那么来看这样的两个定义
来看两段定义:

代码:
arrayA BYTE 1h,2h,3h,4h
arrayB WORD 1000h,2000h,3000h,4000h

我们怎么访问?
我举个例子:

代码:
.data
arrayB WORD 1000h,2000h,3000h,4000h
.code
Mov esi,offset arrayB
Mov eax,[esi]
Add esi,4

知道该注意什么地方了把!

(二)
上面看到了,实际上inc esi这样是很麻烦的。那么好呢容易想到变址操作数。

那么
变址操作数的话,我们可以这样写:

代码:
.data
arrayB WORD 1000h,2000h,3000h,4000h
.code
Mov esi,offset arrayB
Mov eax,[esi]
Mov ebx,[esi+2]
Mov ecx,[esi+4]

那么我们来阐述清楚一个小细节,c语言里比如char aa[2]={0,1};那么printf(“%x”,aa);应该是输出aa的内存 地址的,printf(“%c”,*aa),这样输出了第一个元素0.为什么?因为实际上aa这个名字实际上是aa[0],那么同样asm里面我们也可以 这样考虑。
那么我们这样访问元素:

代码:
.data
arrayB WORD 1000h,2000h,3000h,4000h
.code
Mov esi,0h
Mov eax,[arrayB+esi]
Mov ebx,[arrayB+esi+2]
Mov ecx,[arrayB+esi+4]

这样就更方便了,实际上跟C就没有多大的区别了!

(三)
我们先看个c语言的小例子:

代码:
#include "stdio.h"
#include "stdlib.h"

int main()
{
  char a[2]={1,2};
  for(int i=0;i<sizeof(a);i++)
  {
  printf("%dn",a[i]);
  }
  return 0;
}

输出的结果可想而知:1 2
那么我们也可以这样:

代码:
#include "stdio.h"
#include "stdlib.h"

int main()
{
  char a[2]={1,2};
  for(int i=0;i<sizeof(a);i++)
  {
  printf("%dn",*a+i);
  }
  return 0;
}

结果一样,这是什么意思呢?就是我说过的,数组就是个指针的操作,指针更灵活,也不要一提指针就想起C语言里的这个那个,记住,指针是人的日常生活里广大人名群众喜闻乐见的一种思维方式!——倒

那么用指针的概念,来操作数组的话,asm里面同样可以写:

代码:
.data
Array db 1h,2h,3h,4h
.code
Point PTR BYTE Array

Mov esi,point
Mov eax,[esi]

好了,实际上是很简单的!

对于c里面的a[i]这样的东西你反汇编看下,实际上用的就是变址:

代码:
9:        printf("%dn",a[i]);
0040D738   mov         ecx,dword ptr [ebp-8]
0040D73B   movsx       edx,byte ptr [ebp+ecx-4]

好了,基本就这些东西!
建议你遇到这样的问题要多思考,不要只想着问,因为这些都是基本的程序层面的问题!
用我师傅achillis的话说:这叫编码!
我很赞同这个说法,这些层面的东西都只能叫做编码,只是在遵循一些规则。大牛是什么?
大牛就是充分的了解了这些规则,熟练的变通这些规则,甚至突破规则!

结构化写入小练习

王爽书172页实验七的题

assume cs:code,ds:data,es:table,ss:stack
data segment
db ’1975′,’1976′,’1977′,’1978′,’1979′,’1980′,’1981′,’1982′,’1983′,’1984′,’1985′,’1986′,’1987′,’1988′,’1989′,’1990′,’1991′,’1992′,’1993′,’1994′,’1995′
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514,345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226,11542,14430,15257,17800
data ends
table segment
db 21 dup (‘year summ ne ?? ‘)
table ends
code segment
stack segment
dw    256 dup (?)
stack ends
start:
mov ax,data
mov ds,ax
mov ax,table
mov es,ax
mov ax,stack
mov ss,ax
mov bx,0
mov si,0
mov cx,21

s1:    mov al,[bx]
mov es:[si],al
mov al,[bx+1]
mov es:[si+1],al
mov al,[bx+2]
mov es:[si+2],al
mov al,[bx+3]
mov es:[si+3],al
add bx,4
add si,10h
loop s1

mov bx,0
mov si,0
mov cx,21

s2:    mov ax,84[bx]
mov es:5[si],ax
mov ax,84[bx+2]
mov es:7[si],ax
add bx,4
add si,10h
loop s2

mov bx,0
mov si,0
mov cx,21

s5:    mov ax,168[bx]
mov es:0ah[si],ax
add si,10h
add bx,2
loop s5

mov bx,0
mov si,0
mov cx,21

s6:    mov ax,es:5[si]
mov dx,es:7[si]
div word ptr es:0Ah[si]
mov es:0dh[si],ax
add si,10h
loop s6

mov ax,4c00h
int 21h
code ends
end start

调试运行后,查看下内存:

ok,写入正确。