【汇编】三、访问内存

1.内存中字的存储

3.1
16位的字存储在一个16位的寄存器:
 高8位放高字节,低8位放低字节
16位的字在内存中需要两个连续字节存储:
 低位字节存在低地址单元,高位字节存在高地址单元
字单元:由两个地址连续的内存单元组成,存放一个字型数据(16位)

2.用DS和[address]实现字的传送

3.2-3.4
在8086PC中,内存地址由段地址和偏移地址组成(段地址:偏移地址)
解决方案:DS和[address]配合
 用DS寄存器存放要访问的数据的段地址
 偏移地址用[…]形式直接给出

将10000H(1000:0)中的数据读到al中

mov bx,1000H
mov ds,bx
mov al,[0]
mov ax,[0]这句传送字型数据
mov [0],ax 将寄存器ax中的数据传送到内存

3.DS和数据段

3.5
对于8086PC机,可以根据需要将一组内存单元定义为一个段。
 物理地址=段地址x16+偏移地址
 将一组长度为N (N<64K )、地址连续、起始地址为16的倍数的内存单元当作专门存储数
据的内存空间,从而定义了一个数据段。
将哪段内存当作数据段,段地址如何定,由编程人员在编程时自行安排

add [0],[1] 非法语句
add ds,ax 非法语句

4.栈及栈操作的实现

3.6-3.10
栈是一种只能在一端进行插入或删除操作的数据结构。
栈有两个基本的操作︰入栈和出栈。
 入栈︰将一个新的元素放到栈顶;出栈︰从栈顶取出一个元素。

push ax 将ax中的数据送入栈中
pop ax 从栈顶取出数据送入ax
(以字为单位对栈进行操作)

现今的CPU里都有栈的设计。

问题:
 1、CPU如何知道一段内存空间被当作栈使用?
 2、执行push和pop的时候,如何知道哪个单元是栈顶单元?
回答:
8086CPU中,有两个与栈相关的寄存器:
 栈段寄存器SS:存放栈页的段地址
 栈顶指针寄存器SP:存放栈顶的偏移地址
任意时刻,SS:SP指向栈顶元素

push ax的执行,由以下两步完成。
 (1) SP-SP-2,SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;
 (2)将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶。
pop ax 的执行过程和push ax刚好相反,由以下两步完成。
 (1)将SS:SP指向的内存单元处的数据送入ax 中;
 (2) SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

8086CPU不保证对栈的操作不会超界。
8086CPU只知道栈顶在何处(由SS:SP指示),不知道程序安排的栈空间有多大。

5.关于"段"的总结

P69:段的综述
 我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。这完全是我们自己的安排。
 我们可以用一个段存放数据,将它定义为“数据段”;我们可以用一个段存放代码,将它定义为“代码段”:我们可以用一个段当作栈,将它定义为“栈段”。
我们可以这样安排,但若要让CPU按照我们的安排来访问这些段,就要:
 对于数据段,将它的段地址放在DS中,用mov,add,sub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当作数据来访问;
 对于代码段,将它的段地址放在CS中,将段中第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码段中的指令;
 对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作的时候,比如执行push、pop指令等,就将我们定义的栈段当作栈空间来用。
 一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么也不是。关键在于CPU中寄存器的设置,即CS、IP、SS、SP、DS的指向。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
汇编语言中,直接访问Linux物理内存可以通过"特权级"实现。特权级可以理解为权限级别,越高的特权级别可以访问更多的硬件资源,包括物理内存。 首先,我们需要编写一个内核模块来获取linux物理内存的基址。内核模块是在操作系统内核中加载和运行的代码。内核模块可以使用特权级别访问物理内存。 假设我们定义了一个内核模块,并命名为"phys_mem_mod"。我们可以在模块中使用以下代码来获取物理内存的基址: ``` #include <linux/module.h> #include <linux/kernel.h> void* base_addr; int init_module(void) { base_addr = phys_to_virt(0); //通过物理地址0获取基址 printk(KERN_INFO "Physical memory base address: %p\n", base_addr); return 0; } void cleanup_module(void) { printk("Unloading phys_mem_mod module.\n"); } MODULE_LICENSE("GPL"); ``` 在代码中,我们使用了phys_to_virt()函数将物理内存地址0转换为虚拟地址,并将其存储在base_addr变量中。通过打印base_addr变量,我们可以得到物理内存的基址。 在编写完内核模块代码后,将其编译为ko文件并加载到Linux内核中。加载后,内核模块将输出物理内存的基址。 此外,为了直接访问物理内存,我们还需要在内核模块中使用特殊的指令来读取或写入特定的物理内存地址。具体的操作将根据实际需求而定,并需要注意特权级别的限制。 总之,通过编写内核模块并使用特权级别,我们可以实现在汇编语言中直接访问Linux物理内存。请记住,在进行这样的操作时,需要仔细考虑安全性和操作系统的稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冷冰殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值