У меня есть три рекомендации:
- Посетите 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]. «т» — 116.
tmp$ ./a.out test
tmp$ echo $?
116
tmp$
Изучив сгенерированную сборку, я вижу, что она не использует всплывающие окна, а просто загружает регистры в зависимости от положения параметров стека относительно базового указателя 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