Jak pisać programy w języku asembler pod Linuksem?

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. Jeśli ktoś z Was zna język C, to na pewno wie, jak zadeklarować funkcję główną programu tak, aby mogła odczytać parametry i zmienne środowiska. Deklaracja taka wygląda zazwyczaj tak:

		int main (int argc, char *argv[], char *env[])

gdzie:

Ale gdzie są te zmienne?
Na stosie, oczywiście!
Po wykonaniu typowego prologu do funkcji (czyli push ebp / mov ebp, esp), zmienna argc znajduje się w [ebp+4], wskaźniki do parametrów linii poleceń zaczynają się od [ebp+8] i idą w górę stosu, po nich jest wskaźnik zerowy i dalej w górę są wskaźniki do zmiennych środowiska, też zakończone wskaźnikiem zerowym.

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, z iloma argumentami go wywołano (co najmniej jeden - nazwa programu), wyświetlenie tych argumentów i zmiennych środowiska.

A teraz kod:


(przeskocz program wyświetlający linię poleceń)
; Program wyświetla własną linię poleceń i zmienne środowiskowe.
;
; Autor: Bogdan D.
; kontakt: bogdandr (at) op (dot) pl
;
; nasm -O999 -f elf liniap.asm
; ld -s -o liniap liniap.o bibl/lib/libasmio.a
;
; fasm liniap.asm liniap.o
; ld -s -o liniap liniap.o bibl/lib/libasmio.a

	; przyda się nam moja biblioteczka
%include "bibl/incl/linuxbsd/nasm/std_bibl.inc"
section .text
global _start

; FASM:
; format ELF
; include "bibl/incl/linuxbsd/fasm/std_bibl.inc"
; section ".text" executable
; public _start


_start:
	push	ebp		; typowy prolog, o którym wspomniałem
	mov	ebp, esp

%idefine	argc	ebp+4		; liczba parametrów
%idefine	argv	ebp+8		; parametry

; FASM:
; 	argc	equ	ebp+4		; liczba parametrów
;	argv	equ	ebp+8		; parametry


	mov	eax, [argc]		; EAX = liczba parametrów
	pisz32e				; wypisz EAX
	nwln				; przejdź do nowej linii

	xor	edi, edi		; zerujemy licznik
					; wyświetlonych parametrów

wypisz_argv:
	cmp	edi, eax		; czy liczba wyświetlonych =
					; = liczba parametrów?
	je	koniec_wypisz_argv	; jeśli tak, to koniec
					; wyświetlania parametrów

	mov	esi, [argv+edi*4]	; pobierz parametr numer EDI.
					; każdy wskaźnik jest czterobajtowy,
					; dlatego mnożymy EDI przez 4.

	pisz_esi			; wypisz napis pod adresem ESI
					; czyli nasz parametr
	nwln				; przejdź do nowej linii

	add	edi, 1			; wybieramy kolejny parametr
	jmp	short	wypisz_argv	; i idziemy pisać od nowa

koniec_wypisz_argv:
			; parametry się skończyły. Teraz będzie jeden
			; wskaźnik zerowy i zmienne środowiska

	inc	edi			; przeskocz wskaźnik zerowy

wypisz_env:
        mov     esi, [argv+edi*4]	; pobierz zmienną środowiskową

	test	esi, esi		; sprawdź, czy nie wskaźnik zerowy
	jz	koniec_wypisz_env	; jeśli zero, to skończyliśmy

        pisz_esi			; wypisz zmienną środowiskową
        nwln				; przejdź do nowej linii

        add     edi, 1			; przechodzimy na kolejna zmienną
        jmp     short   wypisz_env	; i wypisujemy dalej


koniec_wypisz_env:
	wyjscie				; koniec...

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ść.