-
十三、直接、寄存器间接寻址、寄存器相对寻址、基址变址寻址、相对基址变址寻址
2019-01-19 17:58:44计算机只容许使用bx、si、di、bp寄存器做间接和相对寻址 其中bx为基址存储器,si、di为变址存储器 内存寻址方式:确定访问内存存储单元偏移地址的方式称为寻址方式。 直接寻址:[偏移地址] 寄存器间接寻址:...计算机只容许使用bx、si、di、bp寄存器做间接和相对寻址
其中bx为基址存储器,si、di为变址存储器
内存寻址方式:确定访问内存存储单元偏移地址的方式称为寻址方式。
直接寻址:[偏移地址]
寄存器间接寻址:[基址寄存器/变址寄存器]
寄存器相对寻址:[基址寄存器/变址寄存器+偏移量值]
基址变址寻址:[基址寄存器+变址寄存器]
相对基址变址寻址:[基址寄存器+变址寄存器+偏移量值]
注意:
a 格式上的注意,正确区分寻址方式
b 五种寻址中,均可以使用段前缀 //ds:[0001H]
c masm编译器编译时,代码中的直接寻址必须采用段前缀的形式
指针寄存器包括堆栈寄存器SP(stack pointer)和基数指针寄存器BP(base pointer),变值寄存器包括源变址寄存器SI(source index)和目的变值寄存器DI(destination index)。这4个寄存器都是16位寄存器,这些寄存器在运算过程中也可以用来存放操作数(只能以字为单位),但经常的用途是在段内寻址时提供偏移地址,SP,BP一般与段寄存器SS联用,以确定堆栈寄存器中某一单元的地址,SP用以指示栈顶的偏移地址,而BP可作为堆栈区中的一个基地址,用以确定在堆栈中的操作数地址。SI,DI一般与段寄存器DS联用,以确定数据段中某一存储单元的地址,SI,DI具有自动增量和自动减量的功能,这一点使在串操作指令中用做变址非常方便,SI作为隐含的源变址DS联用,DI作为隐含的目的变址和ES连用,从而达到在数据段和附加段中寻址的目的。
BX+SI
BX+DI
BP+SI
BP+DI1. 直接寻址
偏移地址值直接出现在执行代码中。
mov 寄存器,[偏移地址] mov [偏移地址],寄存器
2. 寄存器间接寻址
偏移地址通过寄存器取得使用
mov 寄存器,[寄存器] mov [寄存器],寄存器
实例:
assume cs:daima daima segment mov ax,2000H mov ds,ax mov ax,1122H mov cx,3344H mov bx,0000H mov [bx],ax ;将ax值放入ds 2000:0000 mov bx,0002H mov [bx],cx ;将cx值放入ds 2000:0002 mov ax,4c00H int 21H daima ends end
3. 寄存器相对寻址
偏移地址值通过[寄存器+偏移量值]的形式运算后获得。
mov 寄存器,[寄存器+偏移量值] mov 寄存器,ds:[寄存器+偏移量值] mov [寄存器+偏移量值],寄存器 mov ds:[寄存器+偏移量值],寄存器
实例1:
assume cs:code,ds:data data segment db 'abc' data ends code segment start: mov ax,data mov ds,ax mov bx,0000H mov ah,[bx+0000H] mov al,[bx+0001H] mov ax,4c00H int 21H code ends end start
实例2:
;交换ds中偏移地址1和4,2和5,3和6的数据 assume cs:code,ds:data data segment db 'abcdef' data ends code segment start: mov ax,data mov ds,ax mov bx,0000H mov cx,3 A: mov ah,ds:[bx] mov al,ds:[bx+0003H] mov [bx+0003H],ah mov [bx],al inc bx loop A mov ax,4c00H int 21H code ends end start
实例3:
assume cs:code,ds:data data segment db 'abc' db 0H,0H,0H data ends code segment start: mov ax,data mov ds,ax mov si,0000H mov di,0003H mov cx,3 A: mov ah,[si] mov [di],ah inc si inc di loop A mov ax,4c00H int 21H code ends end start
4. 基址变址寻址方式
偏移地址值通过[基址寄存器+变址存储器]的形式运算后获得。
格式:
mov 寄存器,[基址寄存器+变址寄存器] mov [基址寄存器+变址寄存器],寄存器
例如:
mov ax,[bx+si] mov ax.[bx+di] ;不可以这样 mov ax,[si+di]
实例:
;累计相加偏移地址0002H 3次。 assume cs:code,ds:data data segment db 1H,1H,2H data ends code segment start: mov ax,data mov ds,ax mov ah,00H mov bx,0000H mov si,0002H mov cx.3 A: mov al,[bx+si] add ah,al inc bx dec si loop A mov ax,4c00H int 21H code ends end start
5. 相对基址变址寻址
偏移地址值通过[基址寄存器+变址寄存器+偏移量值]的形式运算后获得。
格式:
mov 寄存器,[基址寄存器+变址寄存器+偏移量值] mov [基址寄存器+变址寄存器+偏移量值],寄存器
实例:
;取出1H、3H放入ah、al assume cs:code,ds:data data segment db 0H,0H,0H,1H,2H,3H data ends code segment start: mov ax,data mov ds,ax mov bx,0000H mov si,0001H mov ah,[bx+si+0002H] mov di,0003H mov al,[bx+di+0002H] mov ax,4c00H int 21H code ends end start
-
2、指令寻址与数据寻址(直接寻址、间接寻址、寄存器寻址、寄存器间接...、变址寻址、相对寻址、堆栈寻址)
2020-10-16 14:53:472、指令寻址与数据寻址指令寻址思维导图顺序寻址跳跃寻址数据寻址直接寻址间接寻址寄存器寻址寄存器间接寻址隐含寻址立即寻址总结偏移寻址基址寻址变址寻址相对寻址堆栈寻址比较 指令寻址 思维导图 顺序寻址 由于...指令寻址
思维导图
顺序寻址
由于主存按字编址,所以指令地址每次+1;0-1-2-3-4-5-6-7-8
由于指令字长=2B,主存按字节编址,所以每条指令间隔地址为2;此时PC+1实际上是加了俩个地址;
由于采用变长指令字结构,所以指令字长不确定;当读取指令时,先通过操作码判断是几地址指令,然后在将剩余的操作数取出。此时每条地址指令间隔不定。
跳跃寻址
数据寻址
直接寻址
间接寻址
寄存器寻址
寄存器间接寻址
隐含寻址
立即寻址
总结
偏移寻址
基址寻址
1、用专用的基址寄存器保存程序首地址;或者用通用寄存器指明程序首地址(需要在逻辑地址中取几位指明用哪个通用寄存器作为基址寄存器);
2、物理地址 = 逻辑地址 + 基址地址变址寻址
与基址寻址的区别:
1、基址寄存器只能由操作系统管理用户不能管理;而变址寄存器用户可以管理
2、变址寄存器中的内容作为偏移量,形式地址作为基地址;(与基址寻址刚好相反)
PS:基址&变址复合寻址
相对寻址
1、当程序内代码片段移动时,跳转指令采用直接寻址会出现错误;若采用相对寻址,则不论怎么移动都只与PC有关。
2、实际位置与PC指针与偏移量有关
3、硬件如何实现数的“比较”?
堆栈寻址
硬堆栈:不需要访存
软堆栈:每次访问都需要进行访存比较
-
mips的绝对寻址和相对寻址
2019-09-04 12:46:59本文针对龙芯处理器介绍mips的两种重定位类型,绝对寻址和相对寻址。 首先你要知道MIPS中跳转指令有两种bal和jal。bal指令格式如下: jal指令格式如下: 两者的区别如下表: 指令 指令格式 寻址...不同的处理器指令对于地址的格式和方式都不一样。《程序员的自我修养》一书在4.2章节介绍了x86平台的符号解析和指令修正方式。本文针对龙芯处理器介绍mips的两种重定位类型,绝对寻址和相对寻址。
首先你要知道MIPS中跳转指令有两种bal和jal。
bal指令格式如下:
jal指令格式如下:两者的区别如下表:
指令 指令格式 寻址范围 寻址方式 重定位类型 bal I格式(6/5/5/16) 128KB(2的16次方 ×4) 相对寻址 R_MIPS_PC16 jal J格式(6/26) 256MB(2的26次方×4) 绝对寻址 R_MIPS_26 下面通过一段代码分析bal和jal的跳转方式区别:
二、环境准备
为了说明bal和jal的指令修正算法和寻址过程,我准备main.c、test.S和 ld.lds 3个文件。具体代码如下:
## main.c extern __export_parasite_head_start(); int main(){ __export_parasite_head_start(); return 0; } int test(){ char* str = "hello world\n"; int len = 12; /*输出字符串str到终端*/ asm( ".set noreorder \n\t" "li $2,5001\n\t" //sys_write syscall id is 5001 -> v0 "li $4,0\n\t" //stdio file id is 0 -> a0 "move $5,%0\n\t" // fixme: *str value -> a1 "move $6,%1\n\t" //length(*str) is 13 -> a2 "syscall \n\t" "break \n\t" : :"r"(str),"r"(len) :"$2","$4","$5","$6"); return 0; }
注意:main.c里面没有引用任何gcc库函数。
在看看test.S文件的内容:#define __ALIGN .align 4 #define ENTRY(name) \ .globl name; \ __ALIGN; \ .type name, @function; \ name: #define END(sym) \ .size sym, . - sym .section .head.text, "ax" ENTRY(__export_parasite_head_start) .set noreorder bal test jr $31 END(__export_parasite_head_start)
这里的bal test会跳转到main.c里面的test( )。
在看看链接脚本文件ld.lds
OUTPUT_ARCH(mips) ENTRY(main) /*指定了程序入口函数*/ SECTIONS { . = 0x120000000; /* 指定了起始虚地址位置*/ tinytext : { *(.head.text) *(.text*) *(.data) *(.rodata) } /DISCARD/ : { /*释义:需要丢弃的输入段*/ *(.comment) *(.pdr) } . = ALIGN(4); }
关于链接脚本的语法和含义,在之前的文章中稍有提到,可以参考××
接下来我们把main.c和test.S分别用gcc编译成main.o和test.o文件。然后使用ld命令链接main.o和test.o文件生成最终可执行文件test,链接过程使用我写的ld.lds链接脚本,而非默认链接脚本。
$ gcc -c -fno-builtin -mno-abicalls main.c -o main.o $ gcc -c -fno-builtin -mno-abicalls test.S -o test.o $ ld -static -T ld.lds test.o main.o -o test
在分析bal和jal的寻址原理之前。我们可以运行一下test,看看效果
$ ./test hello world Trace/breakpoint trap (核心已转储)
可以看出,这个程序是可以在mips平台上运行的。这段代码的执行流程是:
1、ld.lds文件里面通过ENTRY(main)指定了程序的执行入口是main.c里面的 int main( )函数。
2、main函数里面调用__export_parasite_head_start(),它是在test.S里实现,ENTRY(__export_parasite_head_start)和END(__export_parasite_head_start)。
3、test.S里面通过 bal test 跳转到main.c里的int test()函数。
4、test函数里面通过一段内嵌汇编指令 打印出“hello world”后停住。在这里 Trace/breakpoint trap (核心已转储) 即为上面的break指令执行结果。
接下来我们就开始通过bal和jal指令分析MIPS的相对寻址和绝对寻址。
三、寻址分析
首先使用objdump命令来反汇编test
$ objdump -D test > test.dump
使用"vim test.dump"文件可以查看到如下信息(有些信息在此略过,没有显示)
(1)jal指令的绝对寻址
什么叫绝对寻址呢?绝对寻址就是在指令格式的地址的字段中直接指出操作数在内存的地址。由于操作数的地址直接给出而不需要经过某种变换,所以称这种寻址方式为直接寻址方式。MIPS文档中描述为not PC-relative,即PC无关寻址。
绝对地址寻址是要依赖基地址+偏移。在这里的基地址就是0x120000000 (在ld.lds 里面指定)。
看上面的jal跳转指令:12000006c: 0c000014 jal 120000050 <__export_parasite_head_start>
当前jal寻址计算为: 0x120000000 + 0x14<<2 正好是__export_parasite_head_start的入口地址0x120000050。
再看指令0c000014是怎么回事?上面我们知道jal的指令格式是高6位代表jal指令码(0x0c),低26位存贮偏移地址右移2位后的结果值(0x50右移2位后结果为0x14)。(2)bal指令的相对寻址
什么叫相对寻址呢?与基址变址寻址方式相类似,相对寻址以程序计数器PC的当前值(R15中的值)为基地址,指令中的地址标号作为偏移量,将两者相加后得到操作数的有效地址。MIPS文档中描述为PC-relative,即PC相关寻址。
相对寻址要依赖PC的值(PC就是当前指令的位置)。基本计算规则是加载延迟槽+偏移。加载延迟槽就是紧跟在PC加载指令后的指令位置。对于mips 的32位指令 加载延迟槽=PC+4。如果是64位指令加载延迟槽=PC+8。
看上面的bal跳转指令:120000050: 0411000e bal 12000008c <test> 120000054: 03e00008 jr ra
当前bal跳转指令的寻址计算为:0x120000054 + 0xe<<2 正好是test函数的入口地址。
这里当前PC为0x120000050,所以加载延迟槽为0x120000054。bal用低6位存储偏移地址右移2位后的结果值。(完)
-
PC值的改变(相对寻址与绝对寻址)
2020-03-19 15:25:37我们知道,计算机中有很多的寄存器,他们是32位的,其中每一位的值要么是0要么是1。在汇编语言中,每一条要...那么在这里有两种寻址方式,相对寻址与绝对寻址。其中beq和bne采用相对寻址,j采用绝对寻址。 相对寻址 ...我们知道,计算机中有很多的寄存器,他们是32位的,其中每一位的值要么是0要么是1。在汇编语言中,每一条要执行的指令都放在一个寄存器中,而这个将要执行指令的地址我们就需要放在PC(程序计数器)中,而这个PC也是32位的,那么此时就有一个可寻址的范围。是从-2的31次方 到 2^31 - 1吗。
那么在这里有两种寻址方式,相对寻址与绝对寻址。其中beq和bne采用相对寻址,j采用绝对寻址。
相对寻址
其中immediate占16位,我们已经知道,每一条指令都要4个字节,那么我们我们这里就以字为单位,immediate * 4就是要跳转的指令个数了。那么这个可以寻址的范围就是从当前指令向上 - 2的15次方 ,向下 PC + 2的15次方 - 1个指令.
如下,其中PC+4这一项是由于硬件原因。可以简单的在Mars上验证一下就可以。
如果进行分支: PC = (PC + 4) + (immediate * 4)
绝对寻址
其中的target address占据26位
现在, 可以指定32位地址中的26位.
优化:
和前面分支跳转一样,将只跳转到字对齐的地址, 因此最后两位总是00.
因此,可以默认最后二位为00,而不必专门指定.
现在指定了32位地址中的28位
其它4位如何得到呢?
我们定义,从PC处取得最高4位.
从技术上讲, 这意味着我们无法跳转到内存的任何地方, 但对99.9999…%的情况,这是正确的,因为程序没有那么长
那么此时的PC就是:New PC = { PC[31…28], target address, 00 }
附上一道例题来加以说明
2.24
对于跳转指令j来说,PC采用绝对寻址,
即PC = PC31…28 : (address × 4),其中address是26位。
如果原地址是PC(原) = 0x20000000
那么按照定义新的PC(新) = 0x2*******
不可能为0x40000000.
对于条件分支指令beq来说,PC采用相对寻址,
即PC = (PC + 4) + (immediate * 4),其中immediate是16位,
每执行一条语句,PC += 4;(0x40000000-0x20000000) / 0x4 = 0x5000000则实际要跳转的指令数为5 * 16^6 - 1 = 5 * 2^24 - 1 >> 2^15 - 1.故对于beq来说不可以。
综上,j和beq指令都不可以将PC的值从0x2000000变为0x4000000. -
web界面中的相对寻址VS绝对寻址
2016-09-29 15:53:101. 相对寻址与绝对寻址的一般规则 相对寻址:当链接到存储在一起的文件(比如都是相同网站的组成部分的文件)时,应使用相对寻址; 绝对寻址:当链接到别的位置(另一台计算机另一个磁盘驱动器获知internet上的另... -
相对寻址问题求解总结
2016-10-02 14:54:38相对寻址的PC自增问题 其他的,现在看来都很直接。虽然曾经学习嵌入式时,很不能理解立即数是什么,后来明白不过是给定位数编码的上下限而已。就一句话总结第一条:基址寻址用在OS多道程序以及编制浮动程序,普通... -
寄存器相对寻址方式
2016-08-27 10:35:54解:根据寄存器相对寻址方式的规则,在执行本例指令时,源操作数的有效地址EA为: EA=(SI)+100H=2345H+100H=2445H 该操作数的物理地址应由DS和EA的值形成,即: PA=(DS)*16+EA=1000H*16+2445H=... -
七种寻址方式(寄存器相对寻址方式)
2018-01-22 19:12:33解:根据寄存器相对寻址方式的规则,在执行本例指令时,源操作数的有效地址EA为: EA=(SI)+100H=2345H+100H=2445H 该操作数的物理地址应由DS和EA的值形成,即: PA=(DS)*16+EA=1000H*16+2445H=... -
-
RIP寄存器相对寻址的问题
2016-12-27 13:52:43在汇编代码 000000000001: mov offset(%rip),rax 中,当前指令地址(rip)为000000000001,如果offset为10,有效地址怎么计算呢?直接rip+offset就可以了吗? -
ARM中关于绝对寻址相对寻址LDR,ADR的理解
2015-11-11 00:28:59LDR:是与位置有关的,是个绝对寻址,其后的地址值是在程序编译的时候就确定位置了. 例如当程序在内部stepping stone中执行时候,如果使用ldr pc, =copy_proc_beg ,则程序就是把copy_proc_beg的绝对地址,即在... -
一次间接寻址的有效地址_寄存器间接寻址和相对寻址有什么区别呢?其实很容易理解的...
2021-01-05 13:23:45寄存器寻址是在指令的操作码后给出寄存器,指令可以操作寄存器中的数据。例如:MOV A,R7这条指令的含义是将寄存器R7中的数据送到累加器A中。如果寄存器R7中的数据为10101001,执行该条指令后,R7中的数据会送到累加... -
从机器码理解RIP 相对寻址
2017-01-19 00:37:00在搜索资料的时候,发现RIP相对寻址这个概念,这并不是一个汇编器的概念,而是CPU的,所以,既然把%rip + displacement这种寻址模式单独拿出来,那么还是会有差别的。 此外,在维基上看到的,RIP相对寻址是在x86-64... -
设相对寻址的转移指令占两个字节,第一字节是操作码,第二字节是相对位移量(用补码表示),若CPU每当从...
2021-01-17 18:44:111.设相对寻址的转移指令占两个字节,第一字节是操作码,第二字节是相对位移量(用补码表示),若CPU每当从存储器取出一个字节时,即自动完成(PC)+1一PC。 设当前PC的内容为2009H,要求转移到2000H地址,则该转移指令... -
【转】ARM中关于绝对寻址相对寻址LDR,ADR的理解
2013-04-17 18:08:00ARM 地址有几个地址概念:编译地址、期望运行物理地址、实际运行物理地址、相对地址、绝对地址、位置无关指令 编译地址 : 编译阶段的生成地址,其是相对地址,有些地址还没确定,如调用其他.O文件中的函数或库函数... -
【汇编程序】实现一维数组求和(相对寻址)
2019-04-13 14:11:42我们在开始写汇编代码的时候,一般是先写出C语言的实现,然后再翻译成汇编的实现。 在这个过程中,我们还可以利用IDE的反汇编功能查看编译器是如何帮我们生成汇编代码的,以及思考编译器为什么这样做,搞懂了这些,...
-
RS、D、JK触发器实验报告.docx
-
部分相干涡旋光束的实验研究
-
轻型社会计算方法来制定应急管理政策
-
团结就是力量 (tarjan,最小表示法)
-
艾里光束对微小颗粒的捕获和输运研究
-
2021年 系统分析师 系列课
-
歌声合成从入门到精通
-
【硬核】一线Python程序员实战经验分享(1)
-
物联网基础篇:快速玩转MQTT
-
ps--利用蒙版调整照片的层次结构
-
MySQL你该了解的那些事【服务端篇】
-
三栏布局的七种方案及优缺点对比总结
-
一种红外图像细节增强和动态范围压缩处理算法
-
激光海表面反射率的机载实验分析
-
热点技术:React性能优化总结
-
Mycat 实现 MySQL的分库分表、读写分离、主从切换
-
SecureCRT 连接 GNS3/Linux 的安全精密工具
-
常见dos命令
-
HTTP常用请求头大揭秘
-
202. 快乐数