NASM 中的ORG 指令简介

在NASM中,其作用是根据org指令中指定的偏移,计算段内数据的各种偏移,即:在原有地址的基础上加上org指定的偏移形成数据的真正偏移地址。这意味着org指令指定的地址与代码加载地址在原则上是可以不同的,但操作上却又往往不可行,因为一旦加载到了非ORG指定的地址,可能引发的众多数据地址计算的错误,除非代码中未用到对内存的寻址。另外,如果不用org指令,则相当于使用org 0,即段内偏移地址为0,当程序的实际加载地址为0时,程序也可以正常执行。
如下例子:

ORG 7c00h

start: mov ax, message

(other codes)

...

message: db "message1",0

ORG指令指定后面的代码从0x7c00开始执行,假设标号message前面的字节数为 10字节,则message的偏移地址为0x7c0a, mov ax, message,相当于mov ax, 7c0ah. start的偏移地址为0x7c00. 如果不使用ORG 7c00h, 则message的偏移地址为0x000a, 则mov ax, message相当于 mov ax, 000ah

那么为什么要使用ORG指令呢?

一个典型的例子就是Linux操作系统的内核引导代码,当PC上电启动时,BIOS会把启动盘的第一扇区加载到内存0x7c00地址处,然后从此地址开始执行。如果不指定ORG 7c00h,则mov ax, message相当于mov ax, 000ah,这显然是不对的。

如下例子会在屏幕上显示“message1”

;example1.s
;nasm -f bin example1.s 
org	7c00h

start:
	mov ax, cs	;当前 cs 为 0
	mov ds, ax
	mov es, ax

	call dispstr
	jmp $
dispstr:
	mov ax,message
	mov bp,ax		;es:bp 字符串地址
	mov cx,dwMsgNumber	;字符串长度
	mov ax,1301h
	mov bx,000ch
	mov dx, 1004h
	int 10h
	ret

message:	db	"message1"
dwMsgNumber	equ	$ - message	;计算字符串长度
times	510 - ($ - $$)	db	0	;填充程序到510 字节
dw	0AA55h				;


如果我们不使用ORG指令指定偏移,那怎么办呢?看如下例子:

;example2.s
;nasm -f bin example2.s
;
BOOTSEG	equ	07c0h
	jmp BOOTSEG:start
start:
	mov ax, cs	;当前 cs 为 07c0h
	mov ds, ax
	mov es, ax

	call dispstr
	jmp $
dispstr:
	mov ax,message
	mov bp,ax		;es:bp 字符串地址
	mov cx,dwMsgNumber	;字符串长度
	mov ax,1301h
	mov bx,000ch
	mov dx, 1004h
	int 10h
	ret

message:	db	"message1",
dwMsgNumber	equ	$ - message	;计算字符串长度
times	510 - ($ - $$)	db	0
dw	0AA55h

程序中是用一条跳转指令jmp BOOTSEG:start 跳转到地址 07c0h:start处,虽然此时程序内标号的偏移地址以0为基础,但是JMP指令执行

段间转移,代码段寄存器CS变更为7c0h,

执行以下指令更新DS, ES段的值

mov ax, cs

mov ds, ax

mov es, ax

所以程序中实际的物理地址为 7c00 + 偏移地址。


补充两个实例, 打印寄存器和偏移值:

使用ORG

  ;Example1
  ;nasm -f bin Example1.s
  ;
  org 7c00h
  
  
  [SECTION .code]
  [BITS 16]
		;
  offsetAddr	equ $ - $$
  
  start:	mov ax,cs
  	mov ds,ax
  	mov ax, 0b800h
  	mov es,ax
  	mov ah, 0fh
  
  ;打印CS的值为:0
  	mov ax, cs
  	mov di, ((80 * 9 + 0) * 2)
  	call DispSetup
  	
  	mov ax, cs
  	shr ax, 8
  	mov di, ((80 * 9 + 2) * 2)
  	call DispSetup
  ;打印标号start的值为:7c00h
  	mov ax, start
  	mov di, ((80 * 10 + 0) * 2)
  	call DispSetup
  	
  	mov ax, start
  	shr ax, 8
  	mov di, ((80 * 10 + 2) * 2)
  	call DispSetup
  	;打印offsetAddr 的值为: 0
  	mov ax, offsetAddr 
  	mov di, ((80 * 11 + 0) * 2)
  	call DispSetup
  
  	mov ax, offsetAddr 
  	shr ax, 8
  	mov di, ((80 * 11 + 2) * 2)
  	call DispSetup
  
  	jmp $
  	
  	;显示一个8位寄存器的值
  	;al:数据,di:位置
  	;如Bl = 0xab, 则显示为ba
  DispSetup:
  	mov cx, 2
  	mov bl, al
  .loop:	and al, 0fh
  	cmp al, 9
  	ja .1
  	add al, '0'
  	jmp .2
  .1:	sub al, 0ah
  	add al, 'A'
  .2:	
  .disp:	mov ah, 0fh
  	mov [es:di], ax
  	add di, 2
  	mov al, bl
  	shr al, 4
  	loop .loop
  	ret
  
  times 510-($-$$) db 0
  dw 0aa55h

不使用ORG

  ;Example4
  ;nasm -f bin Example4.s
  ;
  
  BOOTSEG		equ	07c0h
  
  [SECTION .code]
  [BITS 16]
  
  jmp BOOTSEG:offsetAddr	;段间跳转,BOOTSEG指示跳转段地址,start指示偏移地址
  			;即跳转到 7c0h:offsetAddr(7c00h + offsetAddr)地址处
  
  offsetAddr	equ $ - $$
  
  start:	mov ax,cs
  	mov ds,ax
  	mov ax, 0b800h
  	mov es,ax
  	mov ah, 0fh
  
  	mov ax, cs
  	mov di, ((80 * 9 + 0) * 2)
  	call DispSetup
  	
  	mov ax, cs
  	shr ax, 8
  	mov di, ((80 * 9 + 2) * 2)
  	call DispSetup
  
  	mov ax, start
  	mov di, ((80 * 10 + 0) * 2)
  	call DispSetup
  	
  	mov ax, start
  	shr ax, 8
  	mov di, ((80 * 10 + 2) * 2)
  	call DispSetup
  	
  	mov ax, offsetAddr 
  	mov di, ((80 * 11 + 0) * 2)
  	call DispSetup
  
  	mov ax, offsetAddr 
  	shr ax, 8
  	mov di, ((80 * 11 + 2) * 2)
  	call DispSetup
  
  	jmp $
  	
  	;显示一个8位寄存器的值
  	;al:数据,di:位置
  	;如Bl = 0xab, 则显示为ba
  DispSetup:
  	mov cx, 2
  	mov bl, al
  .loop:	and al, 0fh
  	cmp al, 9
  	ja .1
  	add al, '0'
  	jmp .2
  .1:	sub al, 0ah
  	add al, 'A'
  .2:	
  .disp:	mov ah, 0fh
  	mov [es:di], ax
  	add di, 2
  	mov al, bl
  	shr al, 4
  	loop .loop
  	ret
  
  times 510-($-$$) db 0
  dw 0aa55h

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值