关于汇编语言中的标号和变量

时间:2021-02-17 01:09:32

%include "pm.inc" ; 常量, 宏, 以及一些说明

org 0100h
jmp LABEL_BEGIN

[SECTION .gdt]
; GDT
;                                         段基址,      段界限     , 属性
LABEL_GDT: Descriptor        0,                0, 0      ; 空描述符
LABEL_DESC_CODE32: Descriptor        0, SegCode32Len - 1, DA_C + DA_32 ; 非一致代码段, 32
LABEL_DESC_VIDEO: Descriptor  0B8000h,           0ffffh, DA_DRW ; 显存首地址
; GDT 结束

GdtLen equ $ - LABEL_GDT ; GDT长度
GdtPtr dw GdtLen - 1 ; GDT界限
dd 0 ; GDT基地址

; GDT 选择子
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
; END of [SECTION .gdt]

[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0100h

; 初始化 32 位代码段描述符
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE32
mov word [LABEL_DESC_CODE32 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE32 + 4], al
mov byte [LABEL_DESC_CODE32 + 7], ah



我的问题:
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
3.org使程序指针的偏移量置为0100h,那么段基址是多少?

10 个解决方案

#1


1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 基址的偏移
2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
=> 这个属于汇编语言编写问题
3.org使程序指针的偏移量置为0100h,那么段基址是多少?
=> org不作用于PC指针,它会告诉汇编器将org下面产生的机器码按照.text文本段开始位置进行偏移;段基址不变

#2


引用 1 楼 HuiyuYang_fish 的回复:
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 基址的偏移
2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
=> 这个属于汇编语言编写问题
3.org使程序指针的偏移量置为0100h,那么段基址是多少?
=> org不作用于PC指针,它会告诉汇编器将org下面产生的机器码按照.text文本段开始位置进行偏移;段基址不变

1.既然是相对于当前段的偏移,该标号是不是不能超出该段的64kb的空间?
2.变量名是不是代表起始地址?

#3


1.既然是相对于当前段的偏移,该标号是不是不能超出该段的64kb的空间?
=> 实模式下是这样的。

2.变量名是不是代表起始地址?
=> 变量名的地址就是偏移地址。

#4


你看的是 Orange's一个操作系统的实现吧,我也在看
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 首先这是初始化32位保护模式下的代码段,是选择子选择描述符后的段基址,对于实模式下是基址的偏移

2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
=> 这个在NASM中文手册里有。解释如下
NASM对于一行中的空格符并没有严格的限制:labels可以在它们的前面有空格,或 
其他任何东西。label后面的冒号同样也是可选的。(注意到,这意味着如果你想 
要写一行'lodsb',但却错误地写成了'lodab',这仍将是有效的一行,但这一行不做 
任何事情,只是定义了一个label。运行NASM时带上命令行选项'-w+orphan-labels'
会让NASM在你定义了一个不以冒号结尾的label时警告你。  

3.org使程序指针的偏移量置为0100h,那么段基址是多少?
=> org不作用于PC指针,它会告诉汇编器将org下面产生的机器码按照.text文本段开始位置进行偏移;段基址不变
这个回答感觉有点模糊,我理解的是由于此程序是要在DOS下以.com文件执行,而.com有256字节的DOS头部,所以需要跳过这个头部,使程序在0100h开始编译执行

#5


引用 4 楼 arthasmingjing 的回复:
你看的是Orange's一个操作系统的实现吧,我也在看
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 首先这是初始化32位保护模式下的代码段,是选择子选择描述符后的段基址,对于实模式下是基址的偏移

2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
=> 这个在NASM中文手册里有。解释如下
N……

使程序在0100h开始编译执行 你这里的0100h才十六位,物理地址应该是20位

#6


这里段地址是多少? 相对于基址的偏移,这个基址是cs? 这段程序数据和代码是一个段?

#7


引用 5 楼 RJGCSS 的回复:
引用 4 楼 arthasmingjing 的回复:
你看的是Orange's一个操作系统的实现吧,我也在看
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 首先这是初始化32位保护模式下的代码段,是选择子选择描述符后的段基址,对于实模式下是基址的偏移

2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
=> 这个在NAS……


org 0100h是跳过DOS文件头部的256个字节,使.com程序能够正常运行

要了解ORG 0100h,就必须先了解程序段前缀PSP(Program Segment Prefix)

 

程序段前缀是一个操作系统(DOS)概念。当输入一个外部命令或通过EXEC子功能(系统功能调用INT21h,子功能号为4Bh)加载一个程序时,COMMAND确定当前可用内存的最低端作为程序段的起点,也就是程序被加载到内存空间的起点。在程序所占用内存的前256(0100h)个字节中,DOS会为程序创建前缀(PSP)数据区。PSP结构与CP/M中的“控制区域”概念十分接近,这是因为DOS就是从CP/M演变而来的。

 

DOS利用PSP与被加载的程序进行通信。PSP中有程序的返回地址、程序文件名等信息。

1.        16位DOS中,内存的物理地址=段地址*16 + 偏移量,比如段地址0xC0h,偏移量0x50h,则最后的物理地址是0xC0h * 16 + 0x50h = 0xC50h

2.        ORG用来告诉汇编器,程序加载到内存时的初始偏移量为0x100h,用于跳过PSP。 
比如你有一个标号Test的偏移地址是0x0Bh,当编译器看见ORG 0x100h后,就会给这个偏移加上0x100h,编译完成的.com文件中,这个偏移就变成了0x10Bh。 
如果你没有加ORG 0100h,则偏移仍然是0x0Bh,则访问该标号时,就跑到PSP里了,因为程序段的前0100h个字节,都是PSP的数据,而不是用户数据。 
同理,你写ORG 0x200h,则该标号的偏移地址在编译的.com文件中,会变成0x20Bh。

3.        DOS下的.com程序肯定被加载的CS段+0x100h处,因为段的前0100h(256字节)是留给PSP的。这是操作系统DOS的概念,跟ORG没有关系,所以你写ORG 0200h,也不会让程序加载到CS段的0200h处。

4.        JMP、CALL等会改变IP指针的指令所涉及的偏移地址,在程序载入内存后,会自动加上0100h偏移,如你在代码中写JMP 0x0Bh,在程序载入内存后,会自动修正为JMP 0x10Bh。而其他指令不会做自动修正,如你写MOV AX, 0x000Bh,程序载入内存后,仍然是MOV AX, 0x000Bh。

5.        ORG指定偏移是一个编译期概念,编译产生的汇编程序就已经加上了0100h的偏移。而JMP等指令的偏移是在操作系统加载com文件到内存时调整的。

#8


引用 7 楼 arthasmingjing 的回复:
引用 5 楼 RJGCSS 的回复:引用 4 楼 arthasmingjing 的回复:
你看的是Orange's一个操作系统的实现吧,我也在看
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 首先这是初始化32位保护模式下的代码段,是选择子选择描述符后的段基址,对于实模式下是基址的偏移

2.对于声明……

我想问下,如果不申明这个org是不是就不行了?还有难道在连接程序中,不自动改变程序的地址吗?要是多个汇编程序怎么办?(PS:我对这个汇编了解不多)

#9


引用 7 楼 arthasmingjing 的回复:
引用 5 楼 RJGCSS 的回复:引用 4 楼 arthasmingjing 的回复:
你看的是Orange's一个操作系统的实现吧,我也在看
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 首先这是初始化32位保护模式下的代码段,是选择子选择描述符后的段基址,对于实模式下是基址的偏移

2.对于声明……


非常感谢您耐心地回答,但我还是有个问题,程序加载到内存,是不是从高地址加到低地址(程序的开头在高地址结尾在低地址)?  如果程序中jmp LABEL 对于这条指令在机器码中是相对于基址的偏移量,那么这个基址是谁,cs ? ds? cs:ip? 希望的到您的解答

#10


关于汇编语言中的标号和变量
希望的到各位耐心地解答

#1


1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 基址的偏移
2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
=> 这个属于汇编语言编写问题
3.org使程序指针的偏移量置为0100h,那么段基址是多少?
=> org不作用于PC指针,它会告诉汇编器将org下面产生的机器码按照.text文本段开始位置进行偏移;段基址不变

#2


引用 1 楼 HuiyuYang_fish 的回复:
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 基址的偏移
2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
=> 这个属于汇编语言编写问题
3.org使程序指针的偏移量置为0100h,那么段基址是多少?
=> org不作用于PC指针,它会告诉汇编器将org下面产生的机器码按照.text文本段开始位置进行偏移;段基址不变

1.既然是相对于当前段的偏移,该标号是不是不能超出该段的64kb的空间?
2.变量名是不是代表起始地址?

#3


1.既然是相对于当前段的偏移,该标号是不是不能超出该段的64kb的空间?
=> 实模式下是这样的。

2.变量名是不是代表起始地址?
=> 变量名的地址就是偏移地址。

#4


你看的是 Orange's一个操作系统的实现吧,我也在看
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 首先这是初始化32位保护模式下的代码段,是选择子选择描述符后的段基址,对于实模式下是基址的偏移

2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
=> 这个在NASM中文手册里有。解释如下
NASM对于一行中的空格符并没有严格的限制:labels可以在它们的前面有空格,或 
其他任何东西。label后面的冒号同样也是可选的。(注意到,这意味着如果你想 
要写一行'lodsb',但却错误地写成了'lodab',这仍将是有效的一行,但这一行不做 
任何事情,只是定义了一个label。运行NASM时带上命令行选项'-w+orphan-labels'
会让NASM在你定义了一个不以冒号结尾的label时警告你。  

3.org使程序指针的偏移量置为0100h,那么段基址是多少?
=> org不作用于PC指针,它会告诉汇编器将org下面产生的机器码按照.text文本段开始位置进行偏移;段基址不变
这个回答感觉有点模糊,我理解的是由于此程序是要在DOS下以.com文件执行,而.com有256字节的DOS头部,所以需要跳过这个头部,使程序在0100h开始编译执行

#5


引用 4 楼 arthasmingjing 的回复:
你看的是Orange's一个操作系统的实现吧,我也在看
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 首先这是初始化32位保护模式下的代码段,是选择子选择描述符后的段基址,对于实模式下是基址的偏移

2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
=> 这个在NASM中文手册里有。解释如下
N……

使程序在0100h开始编译执行 你这里的0100h才十六位,物理地址应该是20位

#6


这里段地址是多少? 相对于基址的偏移,这个基址是cs? 这段程序数据和代码是一个段?

#7


引用 5 楼 RJGCSS 的回复:
引用 4 楼 arthasmingjing 的回复:
你看的是Orange's一个操作系统的实现吧,我也在看
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 首先这是初始化32位保护模式下的代码段,是选择子选择描述符后的段基址,对于实模式下是基址的偏移

2.对于声明GdtPtr的时候貌似加不加冒号都无所谓
=> 这个在NAS……


org 0100h是跳过DOS文件头部的256个字节,使.com程序能够正常运行

要了解ORG 0100h,就必须先了解程序段前缀PSP(Program Segment Prefix)

 

程序段前缀是一个操作系统(DOS)概念。当输入一个外部命令或通过EXEC子功能(系统功能调用INT21h,子功能号为4Bh)加载一个程序时,COMMAND确定当前可用内存的最低端作为程序段的起点,也就是程序被加载到内存空间的起点。在程序所占用内存的前256(0100h)个字节中,DOS会为程序创建前缀(PSP)数据区。PSP结构与CP/M中的“控制区域”概念十分接近,这是因为DOS就是从CP/M演变而来的。

 

DOS利用PSP与被加载的程序进行通信。PSP中有程序的返回地址、程序文件名等信息。

1.        16位DOS中,内存的物理地址=段地址*16 + 偏移量,比如段地址0xC0h,偏移量0x50h,则最后的物理地址是0xC0h * 16 + 0x50h = 0xC50h

2.        ORG用来告诉汇编器,程序加载到内存时的初始偏移量为0x100h,用于跳过PSP。 
比如你有一个标号Test的偏移地址是0x0Bh,当编译器看见ORG 0x100h后,就会给这个偏移加上0x100h,编译完成的.com文件中,这个偏移就变成了0x10Bh。 
如果你没有加ORG 0100h,则偏移仍然是0x0Bh,则访问该标号时,就跑到PSP里了,因为程序段的前0100h个字节,都是PSP的数据,而不是用户数据。 
同理,你写ORG 0x200h,则该标号的偏移地址在编译的.com文件中,会变成0x20Bh。

3.        DOS下的.com程序肯定被加载的CS段+0x100h处,因为段的前0100h(256字节)是留给PSP的。这是操作系统DOS的概念,跟ORG没有关系,所以你写ORG 0200h,也不会让程序加载到CS段的0200h处。

4.        JMP、CALL等会改变IP指针的指令所涉及的偏移地址,在程序载入内存后,会自动加上0100h偏移,如你在代码中写JMP 0x0Bh,在程序载入内存后,会自动修正为JMP 0x10Bh。而其他指令不会做自动修正,如你写MOV AX, 0x000Bh,程序载入内存后,仍然是MOV AX, 0x000Bh。

5.        ORG指定偏移是一个编译期概念,编译产生的汇编程序就已经加上了0100h的偏移。而JMP等指令的偏移是在操作系统加载com文件到内存时调整的。

#8


引用 7 楼 arthasmingjing 的回复:
引用 5 楼 RJGCSS 的回复:引用 4 楼 arthasmingjing 的回复:
你看的是Orange's一个操作系统的实现吧,我也在看
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 首先这是初始化32位保护模式下的代码段,是选择子选择描述符后的段基址,对于实模式下是基址的偏移

2.对于声明……

我想问下,如果不申明这个org是不是就不行了?还有难道在连接程序中,不自动改变程序的地址吗?要是多个汇编程序怎么办?(PS:我对这个汇编了解不多)

#9


引用 7 楼 arthasmingjing 的回复:
引用 5 楼 RJGCSS 的回复:引用 4 楼 arthasmingjing 的回复:
你看的是Orange's一个操作系统的实现吧,我也在看
1.对于最后四行代码中的标号LABEL_DESC_CODE32表示内存首地址还是相对于基址的偏移量?
=> 首先这是初始化32位保护模式下的代码段,是选择子选择描述符后的段基址,对于实模式下是基址的偏移

2.对于声明……


非常感谢您耐心地回答,但我还是有个问题,程序加载到内存,是不是从高地址加到低地址(程序的开头在高地址结尾在低地址)?  如果程序中jmp LABEL 对于这条指令在机器码中是相对于基址的偏移量,那么这个基址是谁,cs ? ds? cs:ip? 希望的到您的解答

#10


关于汇编语言中的标号和变量
希望的到各位耐心地解答