Reh*_*b11 2 x86 assembly x86-16
我刚刚开始阅读有关英特尔8086的内容,并对其内存有疑问.
我读到地址总线是20位宽,这意味着地址空间是1MB,并且这个空间被分成段.
问题是:
四个段寄存器,CS,DS,SS和ES,他们是只读或者我可以设置自己的价值观,这是他们的默认值?
我看到了以下的汇编教程:
ORG 100h
MOV AX, 0B800h ; set AX = B800h (VGA memory).
MOV DS, AX ; copy value of AX to DS.
MOV CL, 'A' ; CL = 41h (ASCII code).
MOV CH, 01011111b ; CL = color attribute.
MOV BX, 15Eh ; BX = position on screen.
MOV [BX], CX ; w.[0B800h:015Eh] = CX.
RET
Run Code Online (Sandbox Code Playgroud)关于第一行,这是否意味着此代码将存在0x100于代码段空间或整个地址空间中的地址中
和行:
MOV [BX], CX
Run Code Online (Sandbox Code Playgroud)
这是否意味着每次我在MOV指令中引用地址时,都应该从数据段的起始地址估算地址?(因为他写道,目的地是值+数据段reg中的值)
小智 9
首先,我不得不指出你似乎在这里谈论8086"真实模式"寻址,这是一种非常古老的做事方式,几乎没有任何用处.几乎所有现代操作系统都在"保护模式"下运行,它支持许多增强功能(例如平坦的32位和64位内存空间寻址,虚拟内存等),这些增强功能可以改变所有这些功能.
据我所知,现在大多数操作系统都没有任何方法可以运行这样的代码(在实模式下),所以如果你有兴趣为了编程现代PC而学习汇编,你可能想要找一些最新的资料来学习.
话虽如此,假设您确实有理由想要这样做(例如使用某些嵌入式处理器),或者只是出于历史目的而好奇:
是的,可以修改8086实模式段寄存器.执行此操作的指令和选项比修改更通用的寄存器更有限(例如,没有指令只将值直接加载到段寄存器中,这就是为什么在您引用的代码中,值为首先加载到AX,然后AX加载到DS),也可以根据您正在使用的段寄存器而变化.
通常,您永远不会想直接修改CS("代码段")寄存器,因为这会导致立即更改处理器正在运行的代码(可能以您真正不想要的方式).通常的修改方法CS是使用"长跳转"或"长调用"指令,它将同时更新两者CS和IP(指令指针).同样地,SS("堆栈段")通常在程序执行开始时设置,并且从不改变(但从技术上讲,如果你有一些非常有说服力的理由可以这样做).
DS并且ES是通用数据段寄存器,程序更改这些是相当常见的,但是他们希望最好地访问他们想要使用的内存(如上面的示例代码所示).
至于这些寄存器的初始值,这些寄存器通常在调用程序代码之前由操作系统确定.传统上,在MS-DOS中,有两种编写程序的方法,如.COM文件或.EXE文件.(ORG 100h上面代码中的行表明它打算作为COM程序运行.)在COM情况下,MS-DOS最初将所有段寄存器设置为相同CS(即,它们都是在调用程序之前指向DOS决定在内存中加载程序的任何地方.EXE文件格式稍微复杂一些,并允许指定一个单独的"数据段",在这种情况下操作系统将设置DS和ES改为在启动程序之前指向该段.在EXE程序中,DOS通常也会为它们设置单独的堆栈段(SS).
The ORG 100hline告诉汇编程序"假设以下代码将在地址100h加载".在实模式代码中,这样的地址总是相对的CS(因此程序实际上可以加载到内存中的许多位置,只要CS设置为正确的值以使代码相对于100h CS).
数据操作的大多数地址(例如MOV)将DS默认相对于计算(对于某些指令,您可以通过明确指定要使用的不同段来更改它,但是否以及如何执行此操作取决于操作码和您的方式'正在使用它).但是,有一些指令默认设计为使用其他段.总之,最好阅读您想知道的每个操作码的文档,以确定它如何使用哪个段注册.