Esqueceu de declarar argc e argv em main? Sem problemas… não é preciso declarar esses parâmetros manualmente, basta uma variável local e tudo se resolve.
/** * by Daemonio (Marcos Paulo Ferreira) * daemoniolabs.wordpress.com * * Thu Jun 9 22:27:26 BRT 2011 * **/ #include int main() { int i = 0; while( *(&i+50+i) != NULL ) { printf("Argumento %d: %s\n", i, *(&i+50+i++)) ; } return 0; }
Introdução
No formato ELF para arquivos binários, o sistema operacional reserva um pedaço de memória para armazenar os parâmetros da linha de comando e as variáveis do sistema. Sabe-se que esses parâmetros estão na parte de cima da stack no layout de memória de um executável.
Em C, você tem acesso aos argumentos da linha de comando através das variáveis argc e argv declaradas em main. O legal é que, mesmo se você não declarar essas variáveis, os parâmetros ainda serão acessíveis, pois eles não dependem da linguagem C e sim de um padrão para arquivos executáveis.
Encontrando o deslocamento “mágico”
Quando se declara uma variável local, o valor dela estará na pilha, dentro do stack frame da função em que ela reside. Através do operador & podemos encontrar a posição exata na pilha em que uma variável local ocupa. Como visto na introdução, os parâmetros da linha de comando estão em endereços mais altos da pilha e assim é possível calcular um deslocamento entre uma variável local até o primeiro parâmetro da linha de comando.
Qualquer variável local de qualquer função pode ser escolhida como base para se calcular esse deslocamento já que todas elas estão na pilha e abaixo da posição dos parâmetos. Aqui utilizarei uma variável na stack frame de main.
Para encontrar essa constante mágica devemos criar um programa em C que mostre a diferença entre o endereço da variável local e argv. Veja:
/* * Programa que calcula o deslocamento * de uma variavel local ate a localizacao * da lista de parametros da linha de comando. */ #include int main(int argc, char **argv) { int i ; printf("%p\n%p\n", &i, argv) ; return 0; }
Compilando e executando:
$ gcc -o prog1 prog1.c $ ./prog1 0xbfe5ab1c 0xbfe5abe4 $ ./prog1 0xbf9f085c 0xbf9f0924 $ ./prog1 0xbfcc94fc 0xbfcc95c4
Em cada execução, observa-se que são gerados endereços diferentes tanto para i quanto para argv. Porém, se você calcular a diferença entre esses endereços você verá que &i está a 200 bytes abaixo de argv. Note que o valor 200 pode não ser o mesmo em seu sistema.
Concluímos então que:
argv = &i + 200 bytes
Mas como i é inteiro de 32-bits precisamos dividir 200 por 4, e assim descobrimos o deslocamento correto:
argv = &i + 50
Basta agora utilizar o endereço &i+50 no lugar de argv. É bom lembrar também que a string de argv[0] é acessível em *(&i + 50)
, e que argv[1] é acessível em *(&i+50+1)
, e por aí vai. Por fim, o último parâmetro é sempre NULL de acordo com a especificação ELF.
t+