在学习了英特尔8080结构之后,我现在正在尝试学习英特尔8086以及这里的程序是如何布局的。就目前而言,即使查看基本示例也是非常令人生畏的,更糟糕的是,我无法区分两种编写8086代码的方法,我偶然发现了。也就是说,有时候我会看到:
.model small
.stack 100h
.code
start:
mov dl, ‘a’ ; store ascii code of ‘a’ in dl
mov ah, 2h ; ms-dos character output function
int 21h ; displays character in dl register
mov ax, 4c00h ; return to ms-dos
int 21h
end start
虽然我也发现:
Progr segment
assume cs:Progr, ds:dataSeg, ss:stackSeg
start: mov ax,dataSeg
mov ds,ax
mov ax,stackSeg
mov ss,ax
mov sp,offset top
mov ah,4ch
mov al,0
int 21h
Progr ends
dataSeg segment
dataSeg ends
stackSeg segment
dw 100h dup(0)
top Label word
stackSeg ends
end start
显然,我知道这两者做的事情非常不同,但令我感到困惑的是一般语法有多么不同。在后者我们有一些“段假设”,而在前者它只是.model,.stack和.code(有时.data,从我发现的)。有什么区别吗?我可以选择哪一种更适合我吗?前者看起来更容易理解和更清楚,但我可以使用它而不是后者吗?
答案 0 :(得分:3)
这在很大程度上取决于您所针对的操作系统(或BIOS或裸机),您所定位的可执行格式以及您使用的汇编程序。
您发布的第一个示例是MS-DOS .COM程序,第二个是MS-DOS .EXE程序,我假设它们都使用Microsoft®汇编程序。
如果你想使用GNU汇编程序(例如在MirBSD或GNU / Linux上)来定位i8086 MS-DOS .COM程序,你可以使用它:
.intel_syntax noprefix
.code16
.text
.globl _start
_start: mov ah,9
mov dx,offset msg
int 0x21
/* exit(0); ← this is a comment */
mov ax,0x4C00
int 0x21
msg: .ascii "Hello, World!\r\n$"
将此文件(hw.S
)编译为:
$ gcc -c -o hw.o hw.S
$ ld -nostdlib -Ttext 0x0100 -N -e _start -Bstatic --oformat=binary -o hw.com hw.o
我在MirBSD / i386下的DOSBOX中测试了结果,并在hexdump中查看它是否正确。
与其他解决方案相比,您不是在汇编文件中定义原点(组织),而是在链接器(ld)命令行中定义。
我还有an example targetting raw x86 BIOS和another one (bootsector for blocklists)以及another one (bootsector for *.tar archives),以防您感兴趣;他们需要不同的起源,即使他们只使用16位模式,也需要i386 CPU。
你不能那样做* .EXE文件。
ELKS也是一个有趣的i8086目标,但我还没有做太多。确保你的GNU版本足够新,以便了解.intel_syntax noprefix
模式。