opa tudo bom? 
milênios depois do meu ultimo tuto aqui...
OBS: Estou utilizando o Assembly x86 na arquitetura IA-32 sintaxe Intel, montador nasm e linkador alink!
bem vamos la, meu objetivo aqui é demonstrar como funciona a "captura" de parametros por linha de comando. Para quem n sabe ou nunca ouviu falar, parametros de linha de comando são os "pós-fixos" do nome de um programa.
Ex:
estamos enviado os parametros "-n", "1" e "localhost" para o comando externo ping
(externo porque na verdade ele eh um arquivo nativo localizado na pasta system32)
no C e no C++, esses parametros são facilmente capturados e "parseados" pelos argumentos
da função main, são eles um inteiro comumente denominado argc e uma matriz de caracteres,
podendo ser char** ou char* [], comumente chamada argv. Sendo que o argc representa
o tamanho da linha de comando (incluindo o nome do arquivo e ignorando-se os espaços) e o argv todos os caracteres digitados na linha de comando, ignorando-se os espaços e incluindo na primeira posição o nome do próprio programa.
Em um programa DOS para realizarmos essa mesma tarefa, ja deixo claro que não é uma coisa muito complexa, pelo contrário, consome "poucas" linhas e funciona de forma similiar à do C e C++, ou seja, basicamente irão existir um contador, para armazenar o tamanho da linha de comando (excluindo o nome do arquivo e levando em consideração os espaços), e uma matriz de 2 nibbles (1 byte) contendo os caracteres digitados ( excluindo o nome do arquivo e levando em consideração os espaços ).
logo, se eu criar um programinha asm e digitar na linha de comando:
o "contador" será atribuido ao tamanho do "pós-fixo" do programa, ou seja 7. E a matriz conterá os caracteres
na sua forma ASCII:
Matriz:
108
97
32
108
97
108
97
Count:
7 Chars
sendo 108 == 'l', 97 == 'a' e 32 == ' '
Segundo o PSP (Program Segment Prefixe), o endereço de memória 80 armazena o número de caracteres da linha de comando, ou seja, será o nosso Argc, no caso de termos passado os parametros "la lala", ele terá o valor 7. A partir do endereço 82 em diante, estão os caracteres passados como parâmetro (incluindo espaços e não levando em consideração o nome do programa.
Pondo em prática
Criei um programa que apenas joga na output os parametros passados a ele, usando o serviço 2 da interrupção 21.
Código:
[SECTION CODE USE16 CLASS=CODE] ; Meu cabeçalho, se quiserem por SEGMENT code tmb vale
..start:
mov si, 0x80 ; Aqui fazemos o registrador Source Index apontar para o endereço 80
lodsb ; o lodsb faz o que seu nome sugere, ele carrega um byte (tamanho da command line) armazenado nesse endereço, e joga em al
cbw ; cbw ( Convert Byte to Word ), é opcional, apenas quero expandir al para ax
mov cx, ax ; movo ax, que agora armazena o tamanho da command line, para o registrador cx
mov si, 0x82 ; agora fazemos o registrador SI apontar para o endereço 82
xor ax, ax ; limpo registrador ax, para manter a consciencia limpa mesmo =)
looping: ; label looping, onde iremos capturar os dados
mov ah, 0x2 ; escolho o serviço para exibir caracteres isolados ( no caso o 2 )
mov dl, byte[si] ; movo o byte ( que representa o caractere ASCII ) que esta armazenado na posição atual de si, para dl
int 0x21 ; chamo a interrupção 21 e exibo o caractere
inc si ; passo para a proxima posição
loop looping ; decrementa cx e reitera o laço, findando apenas quando cx for nulo =)
mov ax, 0x4C00 ; serviço 4C
int 0x21 ; chamo a 21 e finalizo
simples não?
caso vc queira usar os espaços para separar os argumentos, basta implementarmos um parser para isso. Caso queira ignorar os espaços, criamos um parser que continue incrementando sem fazer nada, a cada 32 ( space ) que contiver em byte[si], como podemos ver abaixo:
Código:
push ax ; salvamos ax, pra n sobreescrevermos possiveis dados importantes
mov ax, cx ; jogamos tamanho da commandline em ax
Verify:
or ax, ax
jz end_verify
RMV_SPACE:
cmp byte [si], 0x20 ; verificamose se o caractere atual é um space ( ASCII 0x20 -> 32 )
jne RMV_END ; Caso não seja, saia do loop
inc si ; senão incremente si
dec cx ; e decremente cx ou seja o tamanho da command line
jmp RMV_SPACE ; reitere o loop
RMV_END:
dec ax
jmp Verify
end_verify:
pop ax ; retomamos ax
mov si, 0x82 ; retomamos o endereço inicial da linha de comando
bem pessoal, sei que não sou nenhum profissional para redigir um tutorial nota 10, mas espero que meu "esforço" tenha valido a pena, pois se tem algo que eu gosto é de compartilhar o que eu sei e aprender com o maximo de modestia com todos.
espero que tenham gostado e que eu tenha tirado um peso de alguém
grande abraço