Имам три препоръки:
- Разгледайте http://www.nasm.us/doc/nasmdoc9.html, ако не съм вече,
- Минимизирайте кода, който се опитва да реши вашия непосредствен проблем и
- Проверете събранието, генерирано от C компилатор, ако е възможно, когато сте блокирани.
За да получа argv, мога просто да върна ASCII кода за първия знак в argv[1] от моята програма, за да избегна системното извикване. Системното извикване е различен проблем от получаването на argv, така че избягването му фокусира вниманието върху проблема.
След това мога да компилирам минимална C програма и да прегледам генерирания асембли. Четенето на синтаксиса на AT&T не е толкова лошо, ако помните, че когато отивате в AT&T, което е в Ню Джърси, дестинацията е от дясната страна на САЩ ;)
tmp$ cat main.c
int main(int argc, char *argv[])
{
if (argc > 1)
return argv[1][0];
return 0;
}
tmp$ gcc -Wall -save-temps main.c
Програмата просто връща ASCII кода за първия знак в argv[1]. "t" е 116.
tmp$ ./a.out test
tmp$ echo $?
116
tmp$
Разглеждайки генерирания асембли, виждам, че той не използва pops, а по-скоро просто зарежда регистри въз основа на позицията на параметрите на стека спрямо базовия указател, ebp. Намирам, че харесвам този стил на използване на mov с основния показалец.
Аз не използвам pop по начина, по който се опитвате да направите, така че някой друг може да коментира как се прави това с помощта на pop.
Анотирах малко сборката с коментари за това какво мисля, че се случва. Корекциите са добре дошли.
tmp$ cat main.s
.file "main.c"
.text
.globl main
.type main,@function
main:
pushl %ebp ; push the callers base pointer onto the stack
movl %esp, %ebp ; save esp into the base pointer
subl $8, %esp ; make some room on the stack for main ...
andl $-16, %esp ; but pad to an aligned stack pointer
movl $0, %eax
subl %eax, %esp ; dunno why gcc subtracts 0 from stack pointer
cmpl $1, 8(%ebp) ; compare 1 and argc, which is 8 past the base pointer
jle .L2 ; jump to .L2 if argc <= 1
movl 12(%ebp), %eax ; fetch argv into eax
addl $4, %eax ; skip the first 32 bits at that address
movl (%eax), %eax ; fetch address from the resulting address
movsbl (%eax),%eax ; load byte from that address into eax
movl %eax, -4(%ebp) ; put that byte onto the stack (see note 1.)
jmp .L1
.L2:
movl $0, -4(%ebp)
.L1:
movl -4(%ebp), %eax ; load return value from stack (see note 1.)
leave
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 3.2.2"
tmp$
Нямам под ръка nasm на 32-битова машина и конвенциите за извикване на x86_64 не са същите като тези, с които се занимавате, така че не преведох това асемблиране в синтаксис nasm.
- Компилаторът ще направи някои неща, които ви карат да се почешете по главата и да се чудите: "Това умно ли е или тъпо?" В този случай мисля, че вероятно бих използвал самия eax вместо стека за задържане на върнатата стойност, но понякога гугълът е образователен. Научих защо gcc понякога обича да нулира регистър с "xor reg, reg", например, чрез гугъл.
person
Ed Cashin
schedule
03.11.2013