星海's Blog

老头初学编程

有问题的汇编程序(不知错在哪里)

bios设置为用软盘启动,通过软盘第一扇区内容引导硬盘第一扇区至0:7c00h处,然后引导硬盘系统

 

 

~\桌面\STARTSYS.ASM.html
 1 assume cs:codesg
 2 stack segment
 3     db 32 dup (0)
 4 stack ends
 5 
 6 codesg segment
 7 start:
 8     mov ax,stack
 9     mov ss,ax
10     mov sp,32
11 
12     push cs
13     pop ds
14     mov si,offset starsys ;cs[si]指向starsys段
15 
16     mov ax,0
17     mov es,ax
18     mov di,200h ;es:[di]指向0:200h内存
19 
20     mov cx,offset starsysend-offset starsys
21     cld
22     rep movsb ;将starsys段内容复制到0:200h
23 
24     mov ax,0
25     mov es,ax
26     mov bx,200h
27 
28     mov al,1
29     mov ch,0
30     mov cl,1
31     mov dl,0
32     mov dh,0
33 
34     mov ah,3
35     int 13h  ;调用13h中断,将0:200内容复制到软盘第一扇区
36 
37     mov ax,4c00h
38     int 21h
39 
40 starsys:
41     mov ax,0
42     mov es,ax
43     mov bx,7c00h  ;开机时,系统用0:7c00h存放启动设备第一扇区
44 
45     mov al,1
46     mov ch,0
47     mov cl,1
48     mov dl,80h
49     mov dh,0
50     mov ah,2
51     int 13h ;读取硬盘第一扇区至0:7c00h
52 
53     mov ax,0
54     push ax
55     mov ax,7c00h
56     push ax
57     retf  ;将cs,ip改为0:7c00
58 
59 starsysend:nop
60 
61 codesg ends
62 end start
63 

王爽《汇编语言》程序设计1

 

assume cs:codesg 
data segment 
db '1975','1976','1977','1978','1979','1980','1981','1982','1983' 
db '1984','1985','1986','1987','1988','1989','1990','1991','1992' 
db '1993','1994','1995' 
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000 
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226 
dw 11542,14430,15257,17800 
data ends 
 
tablestr segment
db 840 dup (' ')
tablestr ends
 
stack segment
dw 16 dup (0)
stack ends
 
codesg segment
start:
mov ax,data
mov es,ax
mov di,0
 
mov ax,stack
mov ss,ax
mov sp,32
 
mov ax,tablestr
mov ds,ax
mov si,0
mov bx,0
 
mov cx,21
 
s: mov ax,es:[di] 
mov ds:[si],ax 
mov ax,es:2[di] 
mov ds:2[si],ax 
                 
mov ax,es:54h[di] 
mov dx,es:56h[di] 
add si,10
call dwtoc
sub si,10
     
div word ptr es:0a8h[bx]
  mov dx,0
add si,31
call dwtoc
mov byte ptr ds:5[si],0
sub si,31
          
mov ax,es:0a8h[bx] 
mov dx,0
add si,20
call dwtoc
sub si,20
 
 
add si,40
add di,4
add bx,2
    
loop s
 
mov cx,21
mov dh,3
mov si,0
mov dl,5
mov bx,0
 
s0: push cx
mov cl,4ah
call show_str
inc dh
add si,40
pop cx
loop s0
 
  mov ax,4c00h
int 21h
 
;将dword型数据转为十进制ascii码形式
;ax为例
dwtoc: push cx
push dx
push di
push si
push ax
push bx
mov di,0
dtoc: push ax
mov cx,10
mov ax,dx
mov dx,0
div cx
 
mov bx,ax ;bx为除法结果的高十六位
pop ax
div cx
 
push dx ;余数压栈
mov dx,bx ;此时ax除法结果低十六位,dx为高十六位
 
mov cx,ax
add cx,bx
inc di
jcxz reverse
jmp short dtoc
 
reverse:mov cx,di
 
dtocs: pop bx
add bl,30H
mov byte ptr ds:[si],bl
inc si
loop dtocs
 
dec si
;mov byte ptr ds:[si],0
pop bx
pop ax
pop si
pop di
pop dx
pop cx
ret
 
show_str:push cx 
push si 
push ax 
push di 
push es 
push dx  ;全部压栈   
mov ax,0b800h  ;0页显示 
mov es,ax 
               
mov al,0a0h 
mov ah,0 
mul dh    
;此时ax中存放dh行数的字节数 
mov dh,0 
add dl,dl 
add ax,dx 
mov di,ax 
;di存放显示代码所在的偏移值                 
      mov ah,cl
                                           
display:mov cl,ds:[si] 
mov ch,0 
jcxz short strover 
mov al,ds:[si] 
mov es:[di],al 
inc di 
mov byte ptr es:[di],ah 
inc di
inc si
      jmp short display 
                 
strover:pop dx
pop es
pop di
pop ax
pop si
pop cx
ret
 
codesg ends
end start
 

汇编入门笔记(二)

通常我们用loop指令来实现循环功能,CX寄存器中存放循环次数

在汇编源程序中,数据不能以字母开头

dos中,0:200~0:2ff之间的256字节一般没有其他程序的代码或数据

一般来说,在需要暂存数据的时候,我们都应该 使用栈

汇编入门笔记(一)

Err,为了学习《Linux c一站式编程》要学点汇编

 

 

地址总线的宽度决定了CPU的寻址能力
如:80386地址总线宽度为32根,寻址能力为2^32,4GB (8086 20根,1MB)
数据总线的宽度决定了CPU与其他器件进行数据传送时的一次数据传达量
如:8086数据总线宽度16根,一次可传输的数据为2B,16bit.
    80386为32根,一次为4B,32bit
控制总线的宽度决定了CPU对系统中其他器件的控制能力
 
8086 cpu中所有寄存器都是16位的,可以存放两个字节。(386为4B)
AX、BX、CX、DX这四个寄存器通常用于存放一般性的数据,被称为通用寄存器。
为保证兼容,使原来基于上代CPU编写的程序稍加修改就可以运行在8086之上,8086CPU以上四个通用寄存器可分为两个可独立使用的8位寄存器来使用xH和xL
 
8086 CPU给出物理地址的方法
如上,8086CPU 20位地址总线,可达到1MB寻址能力
但从CPU内部来看8086又是16位结构,如果将地址从内部简单地发出,那它只能送出16位地址,寻址能力只有64KB。所以它采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。
地址加法器采用 物理地址=段地址x16+偏移地址的方法用段地址和偏移地址合成物理地址.段地址x16有一个更常用的说法是左移4位。进一步思考,一个数据的十六(x)进制形式左移1位,相当于乘以16(x).
 
段地址必然为16的倍数,所以一个段的起始地址也一定是16的倍数。
偏移地址为16位,16位地址的寻址能力为64KB,所以一个段的最大长度为64KB。
如:给定段地址1000H,仅!用偏移地址寻址,CPU的寻址范围为“1000H-1FFFFH”,64KB
CPU可以用不同的段地址和偏移值形成同一个地址。
 
8086CPU有4个段寄存器,CS、DS、SS、ES。CS存放指令的地址,DS存放要访问数据的段地址。
IP为指令指针寄存器。在8080CPU中,这是两个最关键的寄存器。
任意时刻,设CS中的内容为M,IP中的内容为N,8086CPU 将从内存Mx16+N(CS:IP)单元开始,读取一条指令并执行。
其工作流程:
(1)从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器
(2)IP=IP+所读取指令的长度,从而指向下一条指令
(3)执行指令。转到步骤1,重复这个过程。
 
在8086CPU加电启动或复位后,CS和IP被设置为CS=FFFFH,IP=0000H。即在刚启动时,CPU从内存FFFF0H单元中读取指令执行。是开机后执行的第一条指令。
 
mov指令不能用于设置CS IP的值。能够改变CS、IP内容的指令被统称为转移指令。
最简单的 jmp CS:IP
 
栈顶的地址存放在SS寄存器中,偏移地址放在SP中。
 
PUSH时 SP-2 然后再进数据
POP时  先出数据 然后SP+2
 
“segment” ends标记一个段的结束
end标志整个程序的结束
 
CX寄存器中存放的是程序机器码的长度
 
DOS中exe的加载过程:
找到一段起始地址为SA:0的容量足够的空闲内存区域
前256字节,存放一个256字节程序段前缀的数据区PSP
程序的地址被设为 SA+10H:0
将该内存区的段地址存入 DS中( DS=SA)
将CS:IP指向(SA+10H:0)
 
PSP的物理地址为 SAx16
该程序的物理地址为
SAx16+256(psp)=SAx16+16x16=(SA+16)x16
可用段地址和偏移地址表示为 SA+10H:0