Я пытаюсь написать домашнее задание, которое заключается в следующем:
напишите простую программу на ассемблере, которая все, что она делает, это вызывает программу на C и отправляет ей аргументы командной строки, чтобы она могла правильно работать с (argc и argv).
Как это может быть сделано? Этот asm нам дали в рамках задания:
section .text
global _start
extern main
_start:
;;code to setup argc and argv for C program's main()
call main
mov eax,1
int 0x80
Итак, я хочу знать, где находятся argc
и argv
? Кроме того, мне просто нужно поместить указатель на argc
в регистр eax
, как при возврате значения в обычную функцию C, а программа C сделает все остальное?
В конце концов, после компиляции моей программы на C со следующим Makefile (как я уже сказал, я новичок в сборке, и это Makefile, данный нам учителем, я не до конца его понимаю):
%.o: %.asm
nasm -g -O1 -f elf -o $@ $<
%.o: %.c
gcc -m32 -g -nostdlib -fno-stack-protector -c -o $@ $<
all: lwca
lwca: lwc.o start.o
ld -melf_i386 -o $@ $^
Запуск ./lwca arg1 arg2
должен привести к argc = 3
и argv[1]=arg1 argc[2]=arg2
ОТВЕТ: Отсутствие ответа полностью решило мою проблему, в конце концов сработало следующее:
pop dword ecx ; ecx = argc
mov ebx,esp ; ebx = argv
push ebx ; char** argv
push ecx ; int argc
call main
call
для функции из скомпилированной библиотеки C, но не для запуска и выполнения другой программы. - person Jacek   schedule 24.11.2017main
. Тот, на который вы ссылаетесь, пишетmain
на ассемблере и вызывает другие функции C. - person Peter Cordes   schedule 24.11.2017nasm -O1
(минимальную оптимизацию) вместо многопроходной оптимизации по умолчанию? - person Peter Cordes   schedule 24.11.2017gdb ./hello
и установить точку останова на_start
и выполнить пошаговый код запуска gcc. Он выполняет значительно больше работы, чем вы ожидаете, в основном проверяя списки конструкторов, чтобы увидеть, нужно ли что-то запускать при запуске перед вызовом main. (В простом приветственном мире они будут пустыми.)main()
— это обычная функция, вызываемая обычным способом (для 32-разрядных систем с аргументами в стеке). - person Peter Cordes   schedule 24.11.2017int 0x80
мы можем сказать, что это Linux. i386 System V ABI говорит, чтоargc
указывает указатель стека при запуске процесса (т. е. при входе в_start
), аargv
начинается на одну запись выше этого. (массив по значению, а не указатель на него). - person Peter Cordes   schedule 24.11.2017execve
для отдельно скомпилированного исполняемого файла, а не заменять/повторно реализовывать код запуска CRT, который вызываетmain
. - person Peter Cordes   schedule 24.11.2017esp
и чтоargv
начинается сesp+4
? Домашнее задание было сформулировано так, как я написал, код сборки, который я ввел, также был передан мне. - person Nivolas   schedule 24.11.2017[esp]
и[esp+4]
в стек с последующим вызовом main не работает. Любые идеи? - person Nivolas   schedule 24.11.2017push
изменяетesp
. Кроме того,main
нужен указатель наargv
, а не на первый элемент. Сам массив находится прямо в стеке.lea eax, [esp+4]
/push eax
/push [esp]
может сработать, если я все правильно понял. О,esp
должно быть выровнено по 16B, прежде чем вы вызоветеmain
. В зависимости от программы, если вы этого не сделаете, может произойти ошибка сегментации. Таким образом, вы должныsub esp, 8
перед отправкой еще 2 аргументов, потому что ABI гарантирует, чтоesp
выровнено по 16B при запуске процесса. Кроме того, обычный запуск CRT передаетenvp
в main. Я предполагаю, что вашmain
не ищет третий аргументenvp
? - person Peter Cordes   schedule 24.11.2017esp
? после каждого нажатия мне нужно выполнитьsub esp, 4
, чтобы в итоге он оставался там, где начал? - person Nivolas   schedule 24.11.2017push [esp]
равноtmp = [esp]
/esp -= 4
/[esp] = tmp
, поэтому одно нажатие изменяет смещение, необходимое для доступа к другим элементам в стеке, на+4
. - person Peter Cordes   schedule 25.11.2017argv
, потому что использовал неправильное смещение для 2-го нажатия.lea eax, [esp+4]
/push eax
/push [eax-4]
могут работать, но используйте отладчик, чтобы увидеть, что вы нажимаете и куда указываетesp
на каждом шаге. (Обратите внимание, что я использовал[eax-4]
вместо[esp+4]
из соображений эффективности и потому, что так проще сделать правильно: мы использовалиlea
для установкиeax
до того, как начали изменятьesp
.) - person Peter Cordes   schedule 25.11.2017push
требуетсяpush dword [eax-4]
для указания размера операнда, но все смещения правильные. Я протестировал его с помощью простогоmain
, использующегоprintf
, поэтому мне пришлось связать сgcc -m32 crt-replacement.o print-args.c -nostdlib -lc
). В любом случае, ваш код эквивалентен, красив и компактен. (Но вы можете сохранить инструкциюmov
, используяpush esp
, которая определена для передачи значенияesp
до push уменьшает его.). - person Peter Cordes   schedule 26.11.2017call main
вы (или ваш профессор) должны использоватьmov ebx, eax
для передачи возвращаемого значенияmain
вsys_exit
вместо того, чтобы exit_status = все, что осталось вebx
. (На самом деле это0
, если вы не измените его перед вызовом main, потому чтоebx
сохраняется при вызове, и Linux инициализирует его до 0. Но ваша версия завершается со статусом = младший байтesp
...) - person Peter Cordes   schedule 26.11.2017atexit
(зарегистрировать функцию, которая будет вызываться послеmain
илиexit()
), зависят от кода CRT, чтобы проверить это (связано: функции выхода / системные вызовы. Он также не инициализирует libc при статической компоновке. (Но этот Makefile вообще не связывает libc.) В любом случае, просто мои 2 цента, что это минимальный стартовый код не делает всего того, что делает версия, предоставленная компилятором. - person Peter Cordes   schedule 26.11.2017