GAS считывает аргумент программы "ошибка сегментации"
Я начинаю изучать ассемблер, и мой выбранный компилятор - GNU AS. Единственное, что ужасно в этом - то, что есть немного документации об AS, это синтаксис и руководство пользователя.
Я написал программу hello world, которая читает текстовый файл (путь к файлу является первым параметром программы) и отображает его содержимое на стандартный вывод. Но когда я запускаю программу, всегда говорят "ошибка сегмента". Немного изменив исходный код, я обнаружил, что столкнулся с проблемой при чтении входных аргументов программы. Если я добавлю путь к файлу в исходный код, проблем не будет, но если я прочитаю его из входного аргумента, произойдет "ошибка сегментации".
Это мой исходный код о чтении входного аргумента
# get file name from argument and put in to ebx
movl 8(%esp), %ebx
# open the file
# movl $path, %ebx
movl $5, %eax
movl $0, %ecx
movl $0666, %edx
int $0x80
Я потратил много времени на чтение входных аргументов в GAS, но нашел только одну очень хорошую статью: NASM - Linux Получение параметров командной строки. Я скопировал код и немного изменил на x64 (моя машина kali x64). Интересно, что я снова столкнулся с "ошибкой сегментации". Какой печальный день!!!
Так что если есть кто-то, кто работал со сборкой в Linux, особенно с GAS или NASM, пожалуйста, помогите мне решить эту проблему.
1000+ спасибо (если возможно) за вашу помощь
Цун.
update1: это мой полный исходный код
.global main
.text
main:
# get file name from parameter and put in to ebx
movl 8(%esp), %ebx
# read path in source code
# movl $path, %ebx
# open the file
# movl $path, %ebx
movl $5, %eax
movl $0, %ecx
movl $0666, %edx
int $0x80
# read the file
movl %eax, %ebx
movl $3, %eax
movl $buf, %ecx
movl $bufSize, %edx
int $0x80
# write to stdout
movl %ebx, %ebp
movl $4, %eax
movl $1, %ebx
movl $buf, %ecx
int $0x80
# close the file
movl $6, %eax
movl %ebp, %ebx
int $0x80
exit:
movl $1, %eax
movl $0, %ebx
int $0x80
.data
path:
.asciz "./hello_world.c"
.bss
.equ bufSize, 1024
.lcomm buf, bufSize
Обновление 2: моя ОС x86_64, и это корень многих проблем, с которыми я столкнулся при программировании сборки в x86_64. с помощью @user35443 и @Jester я, наконец, смогу обойти это: скомпилировать в файл x86 elf, вместо x64 elf. исходный код такой же, как и выше, с небольшим изменением main на _start. И поскольку я компилирую x86 на x86_64, мне нужно что-то: apt-get install gcc-multilib
после этого компиляция выполняется напрямую: as --32 readfile.s -o readfile.o && ld -m elf_i386 readfile.o -o readfile && ./readfile some_text_file
(ps: я не знаю почему gcc -m32 readfile.s
ошибка участника)
.global _start
.text
_start:
# get file name from parameter and put in to ebx
movl 8(%esp), %ebx
# movl $path, %ebx
# open the file
# movl $path, %ebx
movl $5, %eax
movl $0, %ecx
movl $0666, %edx
int $0x80
# read the file
movl %eax, %ebx
movl $3, %eax
movl $buf, %ecx
movl $bufSize, %edx
int $0x80
# write to stdout
movl %ebx, %ebp
movl $4, %eax
movl $1, %ebx
movl $buf, %ecx
# size of write is %edx
int $0x80
# close the file
movl $6, %eax
movl %ebp, %ebx
int $0x80
exit:
movl $1, %eax
movl $0, %ebx
int $0x80
.data
path:
.asciz "./hello_world.c"
.bss
.equ bufSize, 1024
.lcomm buf, bufSize
потому что я сфокусировался на x86_64, я оставлю вопрос открытым на несколько дней, и это мой исходный код для x84_64, который я не могу найти в корне проблемы (возможно, я неправильно использовал соглашение о вызовах x86_64).
.global main
.text
main:
# get file name from parameter and put in to rbx
movq 16(%rsp), %rbx
#movq $path, %rbx
# open the file
# movq $path, %rbx
movq $5, %rax
movq $0, %rcx
movq $0666, %rdx
int $0x80
# read the file
movq %rax, %rbx
movq $3, %rax
movq $buf, %rcx
movq $bufSize, %rdx
int $0x80
# write to stdout
movq %rbx, %rbp
movq $4, %rax
movq $1, %rbx
movq $buf, %rcx
# size of write is %rdx
int $0x80
# close the file
movq $6, %rax
movq %rbp, %rbx
int $0x80
exit:
movq $1, %rax
movq $0, %rbx
int $0x80
.data
path:
.asciz "./hello_world.c"
.bss
.equ bufSize, 1024
.lcomm buf, bufSize
1 ответ
Вот 64-битный порт кода:
.global main
.text
main:
push %rbx # save rbx
# get file name from parameter and put in to rdi
# argv in rsi
# open the file
movq 8(%rsi), %rdi # path
movl $0, %esi # flags
movl $0666, %edx # mode
movl $2, %eax # SYS_OPEN
syscall
movl %eax, %ebx # save fd
# read the file
movl %eax, %edi # fd
leaq buf, %rsi # buf
movl $bufSize, %edx # count
movl $0, %eax # SYS_READ
syscall
# write to stdout
movl $1, %edi # stdout
leaq buf, %rsi # buf
movl %eax, %edx # count
movl $1, %eax # SYS_WRITE
syscall
# close the file
movl %ebx, %esi # fd
movl $3, %eax # SYS_CLOSE
syscall
exit:
xor %eax, %eax # return 0
pop %rbx # restore rbx
ret
.data
path:
.asciz "./hello_world.c"
.bss
.equ bufSize, 1024
.lcomm buf, bufSize
Обратите внимание, что не стоит использовать необработанные системные вызовы из программы, использующей libc. Особенно плохо использовать системный вызов exit, потому что это не оставляет возможности для закрытия библиотеки c. Я удалил системный вызов выхода, но оставил остальные нетронутыми. Номера системных вызовов и соглашение о вызовах отличаются для 64-разрядных. Вы можете получить краткий обзор в Википедии или прочитать документы ABI для полной картины.