Jak pisać programy w języku asembler?

Część 12 - Czego od nas pragną, czyli linia poleceń programu. Zmienne środowiska

Teraz zajmiemy się dość istotną sprawą z punktu widzenia programisty i użytkownika oprogramowania: linią poleceń. Nie wszyscy lubią podawać dane programowi w czasie jego pracy i odpowiadać na pytania o dane. Często (o ile jest to możliwe) można tego oszczędzić i zamiast bezustannie zadawać użytkownikowi pytania, przeczytać, co wpisano nam w linię poleceń. Umożliwia to pisanie programów, które raz uruchomione z prawidłową linią poleceń nie pytają już się o nic a tylko wykonują swoją pracę bez przeszkadzania użytkownikom.

Przejdźmy więc do szczegółów. Wszystkie operacje, które wykonamy, będą się opierać na założeniu, że w swoim programie nie zrobiliście absolutnie nic z rejestrem DS. Jeśli go zmieniliście, to użyjcie tej funkcji (opis oczywiście z Listy Przerwań Ralfa Brown'a):


(przeskocz int 21h, ah=62h)
	INT 21 - DOS 3.0+ - GET CURRENT PSP ADDRESS
        	AH = 62h
	Return: BX = segment of PSP for current process

i otrzymaną w BX wartość wpiszcie do DS.

Mając oryginalny DS (wtedy pokazuje on na Program Segment Prefix - PSP), można w nim znaleźć wiele ciekawych informacji:

Wszystko ładnie wygląda w teorii, ale jak tego używać? Aby odpowiedzieć na to pytanie, napisałem ten oto krótki programik. Jedynym celem jego życia jest wyświetlenie długości jego linii poleceń, samej linii poleceń, numerów segmentów: kodu, danych i środowiska (dla porównania), oraz samych zmiennych środowiskowych (jeśli wyświetla się za dużo lub za mało, można zmienić liczbę na końcu programu - pokażę, którą).

Oto kod (NASM):


(przeskocz kod programu)
; Program wyświetla własną linię poleceń i zmienne środowiskowe.
;
; Autor: Bogdan D.
; kontakt: bogdandr (at) op (dot) pl
;
; kompilacja NASM:
;   nasm -O999 -o liniap.obj -f obj liniap.asm
;   alink liniap.obj  bibl\lib\bibldos.lib -c- -oEXE -m-
; kompilacja FASM (stary format biblioteki - OMF):
;   fasm liniap.asm liniap.obj
;   alink liniap.obj  bibl\lib\bibldos.lib -c- -entry _start -oEXE -m-
; kompilacja FASM (nowy format biblioteki - COFF):
;   fasm liniap.asm liniap.obj
;   ld -s -o liniap.exe liniap.obj bibl\lib\bibldos.a

; dołączamy moją biblioteczkę
%include "bibl\incl\dosbios\nasm\std_bibl.inc"
%include "bibl\incl\dosbios\nasm\do_nasma.inc"

.stack 400h			; program typu EXE musi mieć stos

; FASM (stary format biblioteki - OMF):
; format coff
; include "bibl\incl\dosbios\fasm\std_bibl.inc"
; use16
; public start
; public _start
; i nic poza tym

; FASM (nowy format biblioteki - COFF):
; format coff
; include "bibl\incl\dosbios\fasm32\std_bibl.inc"
; public start
; public _start
; i nic poza tym


start:
_start:
..start:			; miejsce startu programu
	mov	si, 80h	; [ds:80h] - długość linii poleceń bez Entera
	xor	eax, eax
	mov	al, [si]	; AL = długość linii poleceń
	pisz
	db	"Dlugosc linii polecen: ", 0
	pisz8			; wypisujemy AL
	nwln			; przechodzimy do nowej linii

	mov	cx, ax		; CX=długość linii poleceń,
				; abyśmy wiedzieli,
				; ile znaków należy wyświetlić
	inc	si		; SI=81h. [ds:81h] to początek
				; linii poleceń
	pisz
	db	"Linia polecen=", 0
	pisz_dl			; wypisujemy CX znaków spod DS:SI,
				; czyli całą linię poleceń
	nwln

	mov	ax, cs
	pisz
	db	"Segment kodu programu CS=", 0
	pisz16			; wyświetlamy AX=CS
	nwln
	mov	ax, ds
	pisz
	db	"Segment danych DS=", 0
	pisz16			; wyświetlamy AX=DS
	nwln

	mov	ax, [ds:2ch]
	pisz
	db	"Segment zmiennych srodowiskowych: DS:[2ch]=",0
	pisz16			; wyświetlamy AX=segment środowiska
	nwln

	; wyłączyć poniższe linie aż do "wypisz_srod" w przypadku FASMa z
	; nowym formatem biblioteki (32-bitowy COFF nie pozwala na
	; manipulację segmentami)
	mov	ds, ax		; DS = segment środowiska
	xor	si, si		; SI = początek segmentu
	pisz
	db	"Zmienne srodowiskowe: ", 0

	mov	ah, 0eh		; funckja wypisywania znaku
	dec	si		; tylko po to, aby najbliższe INC SI
				; zadziałało prawidłowo i ustawiło nas z
				; powrotem na 0
wypisz_srod:
	nwln			; przejdź do nowej linii
wypisz:
	inc	si		; SI teraz pokazuje na kolejny znak
	cmp	si, 400	; żeby nie było za długo -
			; to tę liczbę MOŻNA ZMIENIĆ
	ja	koniec

	mov	al, [si]	; pobierz znak spod [DS:SI]
	test	al, al		; czy bajt zerowy?
	jz	sprawdz		; jeśli tak, to sprawdzimy,
				; czy nie dwa pod rząd

	int	10h		; wypisz znak
	jmp	short	wypisz	; i w kółko od nowa

sprawdz:
	cmp	byte [si+1], 0
	jne	wypisz_srod

koniec:
	wyjscie

Jak widać, nie było to aż takie trudne jak się mogło zdawać na początku. Właśnie poznaliście kolejną rzecz, która jest łatwa w użyciu, a możliwości której są duże. Teraz będziecie mogli śmiało zacząć pisać programy, których jedynym kanałem komunikacyjnym z użytkownikiem będzie linia poleceń, co znacznie uprości ich obsługę.

Tylko pamiętajcie o dodaniu kodu wyświetlającego sposób użycia programu, gdy nie podano mu żadnych parametrów.



Poprzednia część kursu (Alt+3)
Kolejna część kursu (Alt+4)
Spis treści off-line (Alt+1)
Spis treści on-line (Alt+2)
Ułatwienia dla niepełnosprawnych (Alt+0)


Ćwiczenia

  1. Napisz program, który utworzy plik podany jako parametr. Jeśli podano drugi parametr (oddzielony od pierwszego spacją), zapisz jego wartość do tego pliku. Jeśli nie podano żadnych parametrów, niech program wypisze stosowną wiadomość.

  2. Napisz program, który oblicza NWD (patrz część 8) dwóch liczb podanych na linii poleceń. Jeśli nie podano wystarczającej liczby parametrów, niech program wyświetli stosowną wiadomość.