[youtube]
[vk]
- Читаем число и сразу печатаем
- Складываем два числа
- Условные и безусловные переходы
- Использование 32-битных регистров
- Сдвиги - можно подебажить и посмотреть, что происходит
gcc <file_name> -o <binname>
gcc prog.S simpleio_x64_64.S -o prog
./prog
gcc -S -O0 file.c
Появится файлик file.s
readi32 - считать 32 битное число (сложится в eax)
readi64 - считать 64 битное число (сложится в rax)
writei32 - напечатать 32 битное число (печатается из edi)
writei64 - напечатать 64 битное число (печатается из rdi)
Все библиотечные функции не меняют значения регистров rsp, rbp, rbx, r12, r13, r14, r15.
Если ввод закончен, что флаг CF выставится в 1. Проверить по jc.
Чтобы закончить ввод нужно нажать CTRL+D или произвести ввод из файла cat file.txt | ./a.out
или через echo "1 2 3" | ./a.out
rax rcx rdx rbx rsi rdi rsp rbp r8 r9 r10 r11 r12 r13 r14 r15
64-бит | 32-бит | 16-бит | 8-бит | 8-бит (старший) |
---|---|---|---|---|
rax | eax | ax | al | ah |
rcx | ecx | cx | cl | ch |
rdx | edx | dx | dl | dh |
rbx | ebx | bx | bl | bh |
rsi | esi | si | sil | |
rdi | edi | di | dil | |
rsp | esp | sp | spl | |
rbp | ebp | bp | bpl | |
r8 | r8d | r8w | r8b | |
r9 | r9d | r9w | r9b | |
r10 | r10d | r10w | r10b | |
r11 | r11d | r11w | r11b | |
r12 | r12d | r12w | r12b | |
r13 | r13d | r13w | r13b | |
r14 | r14d | r14w | r14b | |
r15 | r15d | r15w | r15b |
┌──────────────────────────────┐
│ rax │
└───────────────┬──────────────┤
│ eax │
└───────┬──────┤
│ ax │
├──┬───┤
│ah│al │
└──┴───┘
add DST, SRC /* DST += SRC */
sub DST, SRC /* DST -= SRC */
inc DST /* ++DST */
dec DST /* --DST */
neg DST /* DST = -DST */
mov DST, SRC /* DST = SRC */
imul SRC /* (eax,edx) = eax * SRC - знаковое */
mul SRC /* (eax,edx) = eax * SRC - беззнаковое */
and DST, SRC /* DST &= SRC */
or DST, SRC /* DST |= SRC */
xor DST, SRC /* DST ^= SRC */
not DST /* DST = ~DST */
cmp DST, SRC /* DST - SRC, результат не сохраняется, */
test DST, SRC /* DST & SRC, результат не сохраняется */
adc DST, SRC /* DST += SRC + CF */
sbb DST, SRC /* DST -= SRC - CF */
Большинство арифметических инструкций в результате вычисления результата инструкции устанавливают арифметические флаги слова состояния процесса.
Флаг ZF устанавливается, если в результате операции был получен нуль.
Флаг SF устанавливается, если в результате операции было получено отрицательное число.
Флаг CF устанавливается, если в результате выполнения операции произошел перенос из старшего бита результата. Например, для сложения CF устанавливается если результат сложения двух беззнаковых чисел не может быть представлен 32-битным беззнаковым числом.
Флаг OF устанавливается, если в результате выполняния операции произошло переполнение знакового результата. Например, при сложении OF устанавливается, если результат сложения двух знаковых чисел не может быть представлен 32-битным знаковым числом.
Обратите внимание, что и сложение addl, и вычитание subl устанавливают одновременно и флаг CF, и флаг OF. Сложение и вычитание знаковых и беззнаковых чисел выполняется совершенно одинаково, и поэтому используется одна инструкция и для знаковой, и для беззнаковой операции.
jz label /* переход, если равно (нуль), ZF == 1 */
jnz label /* переход, если не равно (не нуль), ZF == 0 */
jc label /* переход, если CF == 1 */
jnc label /* переход, если CF == 0 */
jo label /* переход, если OF == 1 */
jno label /* переход, если OF == 0 */
jg label /* переход, если больше для знаковых чисел */
jge label /* переход, если >= для знаковых чисел */
jl label /* переход, если < для знаковых чисел */
jle label /* переход, если <= для знаковых чисел */
ja label /* переход, если > для беззнаковых чисел */
jae label /* переход, если >= (беззнаковый) */
jb label /* переход, если < (беззнаковый) */
jbe label /* переход, если <= (беззнаковый) */
Нужно компилировать с отладочными символами, добавив -g
gcc -g prog.S simpleio_x64_64.S -o prog
gdb ./prog
list (l)- показать код. l 3 показать код с третей строки
break (b)- установить брейкпоинт. Нужно указать имя функции или строку. b main. Выполнение дойдет до этого места и остановится.
run (r) - запустить программу
info break (i b) - посмотреть брейкпоинты
del <breakpoint num> - удалить брейкпоинт с номером breakpoint_num
layout next (la next) - включить следующий layout
layout regs (la reg) - включить просмотр регистров
step (s) - сделать шаг исполнения (с заходом в функции)
next (n) - сделать шаг исполнения (без захода в функции)
continue (c) - продолжить выполнение до следующего брейкпоинта
refresh - обновить отображение (если все съехало или перекособочилось)
finish - выйти из функции
help <command> - справка по команде
p/t $rax - напечатать регистр eax бинарно
p/z $rax - напечатать регистр eax 16-рично
set $rax=5 - установить значение $eax равное 5
jump main - продолжить выполнение с другого места (не обязательно main, можно указать любое другое место или номер строки)
p/t $rax^3 - напечатать в бинарном виде рузультат выполнения команды $eax XOR 3 (другие логические операции тоже можно использовать)
ctrl+x o - переключиться между панелями (чтобы стрелка вверх работала)
Чтобы асм был в синтаксисе intel, нужно создать файл .gdbinit
в той же папке или выше и поместить туда строку
set disassembly-flavor intel
Этот файл будет выполняться каждый раз, когда запускается gdb, поэтому есть смысл туда поместить команды, которые вы каждый раз запускаете.
Также можно поместить туда строку set history save on
, чтобы история команд сохранялась между запусками.
Указаны быстрые пояснения к сдвигам, котоорые взяты с вики учебник по asm полное описание смотрите в источнике.
До сдвига:
+---+ +----------------------------------+
| ? | | 10001000100010001000100010001011 |
+---+ +----------------------------------+
Флаг CF Операнд
Сдвиг влево на 1 бит:
+---+ +----------------------------------+
| 1 | <-- | 00010001000100010001000100010110 | <-- 0
+---+ +----------------------------------+
Флаг CF Операнд
Сдвиг влево на 3 бита:
+----+ +---+ +----------------------------------+
| 10 | | 0 | <-- | 01000100010001000100010001011000 | <-- 000
+----+ +---+ +----------------------------------+
Улетели Флаг CF Операнд
в никуда
До сдвига:
+----------------------------------+ +---+
| 10001000100010001000100010001011 | | ? |
+----------------------------------+ +---+
Операнд Флаг CF
Логический сдвиг вправо на 1 бит:
+----------------------------------+ +---+
0 --> | 01000100010001000100010001000101 | --> | 1 |
+----------------------------------+ +---+
Операнд Флаг CF
Логический сдвиг вправо на 3 бита:
+----------------------------------+ +---+ +----+
000 --> | 00010001000100010001000100010001 | --> | 0 | | 11 |
+----------------------------------+ +---+ +----+
Операнд Флаг CF Улетели
в никуда
Не отличается от shl
До сдвига:
+----------------------------------+ +---+
| 10001000100010001000100010001011 | | ? |
+----------------------------------+ +---+
Операнд Флаг CF
старший бит равен 1 ==>
==> значение отрицательное ==>
==> "вдвинуть" бит 1 ---+
|
+-------------------------------+
|
V Арифметический сдвиг вправо на 1 бит:
+----------------------------------+ +---+
1 --> | 11000100010001000100010001000101 | --> | 1 |
+----------------------------------+ +---+
Операнд Флаг CF
Арифметический сдвиг вправо на 3 бита:
+----------------------------------+ +---+ +----+
111 --> | 11110001000100010001000100010001 | --> | 0 | | 11 |
+----------------------------------+ +---+ +----+
Операнд Флаг CF Улетели
в никуда
До сдвига:
+---+ +----------------------------------+
| ? | | 10001000100010001000100010001011 |
+---+ +----------------------------------+
Флаг CF Операнд
Циклический сдвиг влево на 1 бит:
+---+ 1 1 +----------------------------------+
| 1 | <--+--- | 00010001000100010001000100010111 | ---+
+---+ | +----------------------------------+ |
Флаг CF V Операнд ^
| |
+------------------->--->--->----------------+
1
Циклический сдвиг влево на 3 бита:
+---+ 0 100 +----------------------------------+
| 0 | <--+--- | 01000100010001000100010001011100 | ---+
+---+ | +----------------------------------+ |
Флаг CF V Операнд ^
| |
+------------------->--->--->----------------+
100
До сдвига:
+----------------------------------+ +---+
| 10001000100010001000100010001011 | | ? |
+----------------------------------+ +---+
Операнд Флаг CF
Циклический сдвиг вправо на 1 бит:
+----------------------------------+ 1 1 +---+
+--- | 11000100010001000100010001000101 | ---+--> | 1 |
| +----------------------------------+ | +---+
^ Операнд V Флаг CF
| |
+-------------------<---<---<----------------+
1
Циклический сдвиг вправо на 3 бита:
+----------------------------------+ 011 0 +---+
+--- | 01110001000100010001000100010001 | ---+--> | 0 |
| +----------------------------------+ | +---+
^ Операнд V Флаг CF
| |
+-------------------<---<---<----------------+
011
- https://github.com/victor-yacovlev/fpmi-caos/tree/master/practice/x86-64
- https://ru.wikibooks.org/wiki/%D0%90%D1%81%D1%81%D0%B5%D0%BC%D0%B1%D0%BB%D0%B5%D1%80_%D0%B2_Linux_%D0%B4%D0%BB%D1%8F_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%81%D1%82%D0%BE%D0%B2_C
- https://github.com/blackav/hse-caos-2020