Основная проблема заключается в том, как вы определяете сегмент кода. Компилятор Watcom C / C ++ при использовании модели памяти SMALL требует, чтобы сегмент кода был вызван _TEXT
с классом CODE
. Это несоответствие между кодом сборки и кодом C приводит к тому, что сегмент кода находится в разных физических сегментах, а call _main0_
перескакивает в неправильное место в памяти, вызывая выбросы исключений и зависание программы или
Вы также можете заставить компоновщик Watcom сгенерировать необходимый СТЕК в DOS EXE, создав сегмент под названием _STACK
с атрибутом STACK
и классом STACK
. Если вы создадите сегмент стека таким образом, вам не нужно будет инициализировать SS: SP в начале вашей программы.
Другие разделы, которые Watcom использует в SMALL модели памяти:
_DATA
сегмент с классом DATA
для чтения / записи данных CONST
сегмент с классом DATA
для строковые литералы (которые не предполагается изменять) CONST2
сегмент с классом DATA
для других данных только для чтения _BSS
сегмент с классом BSS
для неинициализированных данных.
Watcom ожидает, что все сегменты CONST
, CONST2
, _DATA
и _BSS
будут в одной группе с именем DGROUP
. На все данные в одной группе можно ссылаться по имени группы. Когда вы настраиваете DGROUP
так, как ожидает Watcom, тогда все, что вам нужно сделать, это инициализировать DS сегментом DGROUP
, а не отдельными сегментами в группе.
метка, которая начинается с ..
, действует как точка входа DOS, с которой должно начаться выполнение. Таким образом, ..start
используется для создания точки входа в заголовке DOS EXE, сообщающей загрузчику программы, где начать выполнение, когда программа загружается в память.
Пересмотренная версия вашего ассемблерного кода могла бы выглядеть так :
; st.nasm
; DGROUP in watcom C/C++ for small model is:
GROUP DGROUP CONST CONST2 _DATA _BSS
global _small_code_
global _printmsg_
extern _main0_
; Code Segment (16-bit code)
segment _TEXT use16 class=CODE
_small_code_:
; .. denotes the label to be used as the DOS entry point
..start:
mov ax, DGROUP
mov ds, ax
mov ah, 9 ; WRITE_STDOUT
mov dx, hello_msg
int 0x21
call _main0_
; call _printmsg_
; mov ax, 3
mov dx, ax
add dx, hello_msg
mov ah, 9 ; WRITE_STDOUT
int 0x21
mov ah, 0x4c ; EXIT, exit code in al
int 0x21
_printmsg_:
ret
push dx
xchg ax, dx
mov ah, 9 ; WRITE_STDOUT
mov dx, hello_msg ; !!
int 0x21
pop dx
ret ; !! restore AX?
; Read only string literals here
segment CONST class=DATA
hello_msg: db 'Hello, World!', 13, 10, '$'
; Other read only data here
segment CONST2 class=DATA
; Read/Write data here
segment _DATA class=DATA
; Uninitialized data segment
segment _BSS class=BSS
; Stack segment 1k in size
segment _STACK STACK class=STACK
resb 1024
Этот код предполагает, что SS! = DS, однако он должен быть скомпилирован с опцией -Wc,-zu
OW CC, которая передает -zu
в W CC (Watcom Компилятор). -zu
изменяет генерацию кода так, чтобы:
-zu SS != DGROUP (i.e., do not assume stack is in data segment)
Если вы используете sh для установки SS == DS == DGROUP, есть несколько способов сделать это. Один из вариантов, который я могу предложить, - это поместить _STACK
в DGROUP
со всеми другими данными программы. Вам понадобится метка после resb 1024
, например stack_top:
, чтобы вы могли загрузить это смещение в SP при запуске после того, как вы установите SS на то же значение, что и DS * 1074. *. Это изменение приведет к созданию кода сборки, который будет выглядеть так:
; st.nasm
; DGROUP in watcom C/C++ for small model is:
GROUP DGROUP CONST CONST2 _DATA _BSS _STACK
; _STACK has been added to DGROUP so we can set SS==DS==DGROUP
global _small_code_
global _printmsg_
extern _main0_
; Code Segment (16-bit code)
segment _TEXT use16 class=CODE
_small_code_:
; .. denotes the label to be used as the DOS entry point
..start:
mov ax, DGROUP
mov ds, ax
mov ss, ax ; Set stack SS:SP to DGROUP:stack_top
mov sp, stack_top
mov ah, 9 ; WRITE_STDOUT
mov dx, hello_msg
int 0x21
call _main0_
; call _printmsg_
; mov ax, 3
mov dx, ax
add dx, hello_msg
mov ah, 9 ; WRITE_STDOUT
int 0x21
mov ah, 0x4c ; EXIT, exit code in al
int 0x21
_printmsg_:
ret
push dx
xchg ax, dx
mov ah, 9 ; WRITE_STDOUT
mov dx, hello_msg ; !!
int 0x21
pop dx
ret ; !! restore AX?
; Read/Write data here
segment _DATA class=DATA
; Read only string literals here
segment CONST class=DATA
hello_msg: db 'Hello, World!', 13, 10, '$'
; Other read only data here
segment CONST2 class=DATA
; Uninitialized data segment
segment _BSS class=BSS
; Stack segment 1k in size
segment _STACK STACK class=STACK
resb 1024
stack_top: