История изменений
Исправление SZT, (текущая версия) :
Много новой информации сразу, новичек в этом просто утонет.
Ну а я это все поразбиваю на разделы, подразделы.
Самое главное, у новичка будет 2 вопроса: зачем это нужно (отладчик, strace, ltrace, листинги ассемблера) на начальных этапах не понятно.
Это нужно для полного понимания того, как там все работает. Через strace можно посмотреть на то, как делаются системные вызовы, можно рассказать, что для вывода текста в консоль надо сделать некий системный вызов write. Рассказать потом про файловый десктриптор, как его создать(как открыть файл через open, получив соответствующий файловый десктриптор), и как вывести текст в файл вместо стандартного вывода. И потом все это надо позапускать через strace, что вот у нас тут дергается open с путем к файлу, возвращается файловый дескриптор, потом мы его используем чтобы записать что-то в файл. Будут сcылки на всякие документации вроде man 2 open
http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html и советы и почитать там.
Просто написать хелловорд - мало. Надо еще понимать, что он делает системный вызов write в некий файловый дескриптор, и это уже приводит к тому, что на экране терминала появляется некий текс. Надо объяснить, что всякие printf puts это не какие-то магические заклинания, это обертки над системными вызовами т.е. в конечном итоге они пишут в некий файловый дескриптор, используя вызов write. Это понимание я считаю важным и нужным.
Как читать ассемблерный листинг находясь на уровне helloworld по первому и единственному пока языку С, тоже не очень понятно.
Легко. Я просто буду предельно сильно все комментировать, и давать попробовать это поотлаживать в GDB. У меня есть опыт в этом деле. Я в свое время через какой-то TeamViewer в OllyGDB тыкал студентов под виндой в ассемблер, подробно рассказывая про регистры, стек, соглашения вызовов, писали какие-то сортировки на асме, всякие там JE JNE и прочую ерунду. Я знаю как это объяснять, чтобы это было понятно
#include <unistd.h>
#include <string.h>
int main(void)
{
const char *n = "Hello World!\n";
write(STDOUT_FILENO, n, strlen(n));
return 0;
}
.file "h1.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0: # метка
.string "Hello World!\n" # Нуль-терминированная строка
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB35:
.cfi_startproc # это директива GAS что начало процедуры
subq $8, %rsp # отмотать стек (стек растет снизу вверх)
.cfi_def_cfa_offset 16
# Дать сcылку https://stackoverflow.com/questions/7534420/gas-explanation-of-cfi-def-cfa-offset
# и документацию GAS
# https://sourceware.org/binutils/docs/as/CFI-directives.html
# Пока что этот момент можно особо не разжевывать, важно понять про соглашения вызова, принятые в GNU/Linux
# надо сказать про System V AMD64 ABI соглашение вызовов. https://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions
movl $13, %edx # 13 это размер строки (3-й аргумент в edx)
movl $.LC0, %esi # .LC0 это адрес (указатель) строки (2-й аргумент в esi)
movl $1, %edi # 1 это STDOUT_FILENO (1-й аргумент в edi)
call write # Вызов write
xorl %eax, %eax # Зануление eax потому что return 0
addq $8, %rsp # Стекпоинтер вернуть на место
.cfi_def_cfa_offset 8 # Это уже объяснено
ret # Возврат из main
.cfi_endproc # Конец процесса
https://github.com/j123123/GAS_SORT_COUNT_WIN32/blob/master/src/sort.s вот кстати еще один жесткий код, полученный в процессе обучения одного человека асму, сортировка подсчетом. Конечно же он написан крайне непрофессионально и кривой, не спорю.
Еще можно лазить отладчиком вовнутрь уже откомпилированных бинарников, в которых специально делать баги, и потом показывать, как этот баг можно поймать за руку при пошаговой отладке!
Исходная версия SZT, :
Много новой информации сразу, новичек в этом просто утонет.
Ну а я это все поразбиваю на разделы, подразделы.
Самое главное, у новичка будет 2 вопроса: зачем это нужно (отладчик, strace, ltrace, листинги ассемблера) на начальных этапах не понятно.
Это нужно для полного понимания того, как там все работает. Через strace можно посмотреть на то, как делаются системные вызовы, можно рассказать, что для вывода текста в консоль надо сделать некий системный вызов write. Рассказать потом про файловый десктриптор, как его создать(как открыть файл через open, получив соответствующий файловый десктриптор), и как вывести текст в файл вместо стандартного вывода. И потом все это надо позапускать через strace, что вот у нас тут дергается open с путем к файлу, возвращается файловый дескриптор, потом мы его используем чтобы записать что-то в файл. Будут сcылки на всякие документации вроде man 2 open
http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html и советы и почитать там.
Просто написать хелловорд - мало. Надо еще понимать, что он делает системный вызов write в некий файловый дескриптор, и это уже приводит к тому, что на экране терминала появляется некий текс. Надо объяснить, что всякие printf puts это не какие-то магические заклинания, это обертки над системными вызовами т.е. в конечном итоге они пишут в некий файловый дескриптор, используя вызов write. Это понимание я считаю важным и нужным.
Как читать ассемблерный листинг находясь на уровне helloworld по первому и единственному пока языку С, тоже не очень понятно.
Легко. Я просто буду предельно сильно все комментировать, и давать попробовать это поотлаживать в GDB. У меня есть опыт в этом деле. Я в свое время через какой-то TeamViewer в OllyGDB тыкал студентов под виндой в ассемблер, подробно рассказывая про регистры, стек, соглашения вызовов, писали какие-то сортировки на асме, всякие там JE JNE и прочую ерунду. Я знаю как это объяснять, чтобы это было понятно
#include <unistd.h>
#include <string.h>
int main(void)
{
const char *n = "Hello World!\n";
write(STDOUT_FILENO, n, strlen(n));
return 0;
}
.file "h1.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0: # метка
.string "Hello World!\n" # Нуль-терминированная строка
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB35:
.cfi_startproc # это директива GAS что начало процедуры
subq $8, %rsp # отмотать стек (стек растет снизу вверх)
.cfi_def_cfa_offset 16
# Дать сcылку https://stackoverflow.com/questions/7534420/gas-explanation-of-cfi-def-cfa-offset
# и документацию GAS
# https://sourceware.org/binutils/docs/as/CFI-directives.html
# Пока что этот момент можно особо не разжевывать, важно понять про соглашения вызова, принятые в GNU/Linux
# надо сказать про System V AMD64 ABI соглашение вызовов. https://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions
movl $13, %edx # 13 это размер строки (3-й аргумент в edx)
movl $.LC0, %esi # .LC0 это адрес (указатель) строки (2-й аргумент в esi)
movl $1, %edi # 1 это STDOUT_FILENO (1-й аргумент в edi)
call write # Вызов write
xorl %eax, %eax # Зануление eax потому что return 0
addq $8, %rsp # Стекпоинтер вернуть на место
.cfi_def_cfa_offset 8 # Это уже объяснено
ret # Возврат из main
.cfi_endproc # Конец процесса
https://github.com/j123123/GAS_SORT_COUNT_WIN32/blob/master/src/sort.s вот кстати еще один жесткий код, полученный в процессе обучения одного человека асму, сортировка подсчетом. Конечно же он написан крайне непрофессионально и кривой, не спорю. Там еще можно лазить отладчиком вовнутрь уже откомпилированных бинарников, в которых специально делать баги, и потом показывать, как этот баг можно поймать за руку при пошаговой отладке!