王爽-汇编语言-综合研究三-使用内存空间

(一) 研究概述

数据不仅可以存储在寄存器中,还可以存储在内存中。这次我们就研究在C语言中,怎样直接在内存中存储数据。以及这样做的一些延伸问题。另外,在附录研究中,我们还探究了C语言中循环和分支结构的实现。

(二) 研究过程

1) 直接在C语言中使用内存空间

此处援引书中的话:

对于存储空间来说,要使用他们一般都需要给出两个信息:一是指明存储空间所在、是哪个的信息;二是指明存储空间有多大的类型信息。

对于寄存器来说,就需要给出寄存器的名称,寄存器的名称就也包含了他们的类型信息。

对于内存空间来说,就需要给出地址(准确的说,是内存空间首地址)和空间存储数据的类型。

我们知道,在C语言里,用指针型数据来表示内存空间的地址和空间存储数据的类型。比如要向偏移地址为2000h、存储一个字节的内存空间写入一个字符‘a’,我们用如下的方法:

*(char *)0x2000 = ’a’;

第一个‘*’表示要访问的是一个内存空间;

“0x2000”是一个数值(0x表示十六进制),“(char *)”里面的‘*’指明了这个

数值表示一个内存空间地址,“char”指明了这个地址是存储char型数据的内存空间地址。

当然也可以用给出段地址和偏移地址的方法访问内存空间,比如我们要向地址为2000:0、存储一个字节的内存空间写入字符‘a’,如下:

*(char far *)0x20000000=’a’;

“far”指明内存空间的地址是段地址和偏移地址,“0x20000000”中的“0x2000”给出了段地址,“0000”给出了偏移地址。

由此,我们知道了C语言直接访问内存空间的基本方法。

2) 编写一个直接访问内存的C语言程序

我们编写一个程序um1.c如下:

编译链接完成,debug加载反编译如下:

3) 编写一个程序,用一条C语言实现在屏幕中间显示一个绿色的字符“a”

我们编写源程序如下:

编译链接运行,效果如下:

4) 关于全局变量和局部变量

我们分析下面程序中所有函数的汇编代码:

编译链接之后debug加载,反汇编如下。

在这里,我们非常直观的看出。程序中的全局变量,被放在了程序的数据段中,而局部变量则放在了其栈段中。这也正好说明了在每个函数开头,都有push bp;mov bp sp的作用。我们把局部变量放在了栈段中,那我们使用时必然要顺利的找到这个变量。而使用sp的话,假如程序中有入栈出栈的操作,栈顶指针变了,我们就找不我们存放的变量了。所以使用BP这个寄存器,在程序的开始把Sp的值给BP,然后,将SP的值增加,把局部变量的位置留出来。这时,我们可以方便的用BP找到局部变量,而也可以方便的使用栈的功能。函数返回时,BP的值又赋值给SP,函数内的局部变量就消失了。这也就是为什么C语言中局部变量的值只在函数内有效的原因。

5) C语言函数返回值存放在哪儿?

我们研究了变量的存放位置,那么,C语言的函数返回值存放在什么地方呢?我们写如下的程序。

编译链接后反汇编分析:

我们看到020A处,为函数f()的汇编指令。前五句,根据前面的内容,我们很容易理解。但是不同的是,多了一句mov ax,[01AA]。那么这条语句的作用是什么?会不会跟我们函数返回值有关?是不是函数返回值是用AX传出的呢?

我们调试运行程序:g 021d,结果如下

可见,函数的返回值的确是由寄存器ax传出的。

6) 综合分析

我们编写一个程序如下:

首先我们要了解#define和malloc这两条语句。

#define的作用,是宏定义,简单的讲在这里就是将((char *)*(int far *)0x02000000)这条语句用Buffer代替,以后再用到这条语句的时候,直接用Buffer就可以了。

((char *)*(int far *)0x02000000)表面是一个char型的指针,它指向的是0200:0000这个地址。

malloc(X)的作用,是申请X长度的内存。

Buffer=(char *)malloc(20)是申请20个字节的内存单元,将首地址赋值给Buffer指向的内存单元。

理解了这个,我们可以理解这个C程序的内容

我们编译链接,反汇编如下:

我们单步执行中,发现

AX中存放的应该是由malloc申请返回来的。应该是我们申请内存的首地址。

我们继续执行

我们发现这个地址果然是malloc返回来的申请内存的偏移地址。

(三) 附录研究

注:附录研究与内存单元的使用无关,主要是研究C语言中的三种结构。顺序结构我们可以很容易的理解,循环结构和选择分支结构研究如下:

1. C语言中循环结构for语句的实现

C语言中循环语句,for语句是如何实现的呢?我们编写如下程序

我们尽量的减小问题的复杂程度,使其突出我们所要研究的重点。这里循环内并没有其他的语句,仅仅是一条空语句。就是为了便于我们把问题的焦点放在for循环的实现上。

我们编译连接,加载后反汇编查看,如下:

我们可以看到,for的循环是使用了si寄存器,首先将si入栈保存,然后清空si,通过不断自加si的值,然后将si与我们原定的数值进行比较。

那么,如果在for中加入语句的话,那么这条语句会加在哪里呢?

我们分析,jmp 0203这条语句,这应该是转到循环内的。那么,应该是先比较,后执行循环内语句呢?还是先执行循环内语句,后比较呢?

我们接着分析,si的值是从0开始的,最后与5作比较,小于则转跳。如果先比较后执行的话,执行的次数就成了4次,这是不正确的。所以,应该是先执行,后比较。

我们验证:

我们在看jmp,这次直接jmp到了020B,果真是每次循环先执行,后比较。但是同时,我们发现,一进入for循环的时候,他是转跳到了比较语句。这又是为什么呢?

假如我们写这样的C语句:for(i=0;i<1;i++)会出现什么结果?如果不先比较一下的话,循环内语句必然要执行一次。这就是一进入for循环,必须先比较一下的原因。

2. C语言中分支结构if的实现

我们编写一个程序如下:

编译连接后加载查看如下:

我们可以直观的看到,依然是使用cmp,jnz等比较语句来进行程序的选择分支的实现。

所以,参照这个研究,返回头看我们的汇编程序。我们可以更加系统的使用汇编语言,来实现程序的各种选择,循环结构。

(四) 个人感悟

内存单元,寄存器,变量之间的关系到底如何?这次的研究给出了一部分答案。局部变量的内涵,全局变量的内涵,返回值的实现。拿研究C语言后的汇编知识在反观汇编程序的实现,应该会有更深入的理解,更结构化的编程概念。

时间: 2024-10-23 04:10:51

王爽-汇编语言-综合研究三-使用内存空间的相关文章

王爽-汇编语言-综合研究四-不使用main函数编程

(一) 研究目的 使用C语言编程,我们一定要使用main函数么? (二) 研究过程 1) 最初的程序 首先,我们编写一个不写main函数的C语言程序. 程序如下: 在编译的过程中,没有发现错误.在链接的过程中发现出现的错误如下: 链接时出现Undefined symbol ‘_main’ in module c0s 这样的错误信息,可能main函数与c0s.obj这个文件有关系. 这时我们想,C语言编译之后的文件后缀名是什么?是.obj.那汇编语言编译后的文件名是什么?也是.obj.这两个文件有

王爽-汇编语言-综合研究二-使用寄存器

(一) 研究概述 我们为什么必须使用变量?因为我们在编程时必须存储数据.那么如果可以使用别的方法存储数据,我们就可以不必因此目的而使用变量. 用什么方法来存储数据呢?在学习汇编语言是.我们把数据存储在寄存器和内存空间中.那么,在本次试验中,我们研究的是C语言中如何使用寄存器. (二) 研究过程 (1) 编写一个程序url.c 编译链接完成,用debug加载. -u查看如下: 这里的语句比较整齐有逻辑,像是某些功能的实现语句,但是往下-u,几次都看不到所写的语句. 这里,main函数的代码应该是在

王爽-汇编语言-综合研究一-搭建简易C环境

(一) 学习过程: 整个过程分为两个部分: 第一:将TC2.0的环境使用虚拟软盘复制到DOS虚拟机中: 打开WinImage,fileànew,由于TC2.0的环境解压后为2.02M,所以我们在Standard format中选择2.88M. 将TC文件夹放入.保存. 在DOS虚拟机中加载做好的软盘.这时A:\内有TC2.0的所有文件了. 此处援引书中的话: 我们在把一个程序拷贝的一个空的目录后,这个目录下只有这一个程序,然后我们运行它,它可以正确运行,我们就认为这个程序在运行中不需要别的文件.

王爽-汇编语言-综合研究五-函数接收不定量参数

(一) 研究目的 我们知道,在C语言中,函数是可以传递参数的.有些函数在声明是就定义了要传的参数的个数,比如我们定义void a(int i);这说明函数a只接受一个int型参数.而有些函数,比如print函数,是可以接收不定个数的参数的.那函数是怎样接收不定量参数的呢? (二) 研究过程 1) 有限个数的参数 首先我们来看程序是如何传参数的.我们编写一个程序,让他传递有限个参数: 我们编译链接,然后反汇编查看其代码: 我们看其代码,首先,在main函数中,分别将‘a’与2对应的ASCLL码放到

王爽汇编语言(第三版)环境搭建(附PDF及工具下载)

一.前言 最近在学习汇编语言,使用的是读者评价非常高的王爽老师写的<汇编语言>(第三版),为了适应现在各个版本的windows操作系统,所以采用VMWare虚拟机来搭建纯DOS环境. 二.需要的工具 VMware-workstation-12.DOS系统镜像文件.汇编编译器masm和连接器link 百度云下载链接:https://pan.baidu.com/s/1gfz4N67 密码:02y1 三.安装VMware-workstation-12 傻瓜式安装,一直点击下一步就可以(虽然网上也可以

最强大的王爽汇编语言学习环境使用教程

最强大的王爽汇编语言学习环境使用教程 一.前言 这是采用VMwere Workstation 12 pro虚拟机软件,搭建的MS-DOS学习环境,在windowsXP/8/10及linux中均可以使用,在这个环境中,我集成了CCDOS中文系统,pdos中文系统,使用这些系统,可以进行中文输入与显示.还集成了,十分著名的汇编语言调试工具TR,它比debug更加强大.并且集成了适合王爽汇编语言学习的微软汇编语言编译器masm5和dos中最强大的文本编辑器 vim73 for DOS,这是一个支持彩色

JAVA 虚拟机深入研究(三)——Java内存区域

JAVA 虚拟机深入研究(一)--关于Java的一些历史 JAVA 虚拟机深入研究(二)--JVM虚拟机发展以及一些Java的新东西 JAVA 虚拟机深入研究(三)--Java内存区域 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的围城,城外的人想进去,城里的人想出来. Java运行的时候会把内存分为若干个,他们各有各的用途,每块区域的创建和销毁都是相对独立的,有的跟虚拟机一起混,有的则抱着用户的大腿同生共死. 按照第七版的<Java虚拟机规范>规定,JVM所管理的内存包括以下

王爽汇编语言第三版第5章实验4

第(3)小题 下面的程序的功能是将“mov ax,4c00h”之前的指令复制到内存0:200处,补全程序.上机调试,跟踪运行结果. assume cs:code code segment mov ax,     cs       ;cs为程序入口的段地址,我们就是要从这里开始复制 mov ds,ax mov ax,0020h mov es,ax mov bx,0 mov cx,     cx        ;程序刚加载完成时,cx存放的是程序的大小,这里我不确定答案,我试过后看到mov ax,4

王爽&lt;汇编语言&gt;实验十

实验十 3.数值显示(以下程序附带测试程序) 1 ;名称: dtoc 2 ;功能: 将dword型数据转变为表示十进制数的字符串,字符串以0为结尾 3 ;参数: (ax)=dword型数据低字 4 ; (dx)=dword型数据高字 5 ; ds:si指向字符串的首地址 6 ;返回: 无 7 assume cs:code 8 data segment 9 haha dd 4294967295 10 tata dd 16 dup(?) 11 data ends 12 code segment 13