З поверненням.
Давайте виконаємо проект - просту вправу, щоб навчитися використовувати функції, які повертають значення.
Отже, напишіть програму, яка може запропонувати користувачеві ввести слово.
Потім підрахувати кількість символів у цьому слові і вивести повідомлення:
"Word has num characters. Приклад виведення:
Введіть рядок.
Користувач вводить "apple. Він підраховує кількість
символів у тексті "Apple. У цьому випадку це буде п'ять
символів, а потім він надрукує повідомлення: "Apple
має п'ять символів. Увага, спойлер!
Прокрутіть вниз, щоб побачити дизайн рішення, тому поки що не прокручуйте вниз.
Я хочу, щоб ви спробували виконати цю вправу самостійно.
Поставте відео на паузу, щоб спочатку спробувати, а
потім подивіться рішення.
Щасти тобі.
Сподіваюся, ви спробували.
Тож давайте прокрутимо вниз і подивимося на дизайн.
Отже, ми будемо використовувати printf для друку запиту "Введіть слово", а потім використовувати scanf для зчитування
слова і збереження його у змінній word з використанням специфікатора формату %s.
Потім ми роздрукуємо результати ось так, використовуючи цей специфікатор формату.
Перший специфікатор формату %s надрукує слово, а потім символ - ви надрукуєте
слово "has", а потім кількість символів.
Другий специфікатор формату - num_chars.
Num_chars - змінна, цілочисельна змінна, і вона виведе слово "символи", а потім перейде на новий
рядок.
Отже, мета цієї команди - вивести цей рядок.
Отже, це %s.
Це - %d. Ось що це означає:
%s, %d. Тепер нам потрібно перетворити це в асемблерний код.
Отже, коли ви перетворите це в асемблерний код, вам потрібно буде натиснути на рядок для підказки, а потім викликати функцію
print, щоб вивести підказку на екран.
Далі ми відскануємо його.
Тож нам потрібно спочатку підштовхнути параметри.
Отже, ми передаємо змінну word, яка є адресою для зберігання рядка, що вводиться користувачем, а також передаємо
специфікатор формату.
Тоді викличте Сканф. Далі, коли ми хочемо викликати довжину рядка для підрахунку
кількості
символів у слові, то параметром буде довжина рядка word.
Отже, що ми тут робимо, так це вводимо довжину рядка ось тут, ось так:
довжина рядка, а потім слово. Це те, що ми реалізуємо: слово довжиною в рядок.
Отже, щоб реалізувати це слово довжини рядка, нам потрібно спочатку передати параметр,
який є адресою рядка, а потім викликати функцію довжини рядка.
Функція довжини рядка буде зберігати кількість символів у вигляді числа, причому
в регістрі -.
Тож нам потрібно зберегти це в пам'яті.
Тому ми використовуємо інструкцію MOV для копіювання цього значення за адресою пам'яті num_chars.
Отже, num_chars також є адресою.
Це для зберігання цілого числа, і нам потрібно розіменування, тому що ми зберігаємо число, а не рядок.
Після цього ми збираємося надрукувати це повідомлення, тому нам потрібно вводити параметри у зворотному
порядку: вводимо num_char, вводимо word, а потім вводимо рядок.
Отже, три параметри: один, два, три.
Отже, це три параметри у зворотному порядку.
Натискаємо слово - маємо розіменування; маємо розіменовувати адресу, щоб отримати ціле число, яке там зберігається.
Потім ми виштовхуємо слово, яке є рядком, а потім виштовхуємо специфікатор формату рядка до стеку.
Отже, три параметри для printf знаходяться у стеку.
Потім викликаємо printf. Отже, давайте реалізуємо це у нашому x64dbg.
Відкриваємо шаблонний і переходимо до нашої пам'яті.
Ми виділимо пам'ять для всіх цих рядків і змінних.
Тож давайте зробимо це зараз.
Спочатку нам потрібно зберегти цей рядок.
Отже, переходимо до карти пам'яті, сегменту даних, і тут ми можемо використати це порожнє місце для рядка.
Рядок має вигляд "Введіть слово. Введіть слово.
Клацаємо правою кнопкою миші тут і вибираємо бінарне редагування, текст "Введіть слово", ставимо двокрапку і пробіл, а потім натискаємо "ОК".
Потім ми копіюємо цю адресу пам'яті і вставляємо її сюди.
Далі нам потрібно зберігати
- нам потрібно створити змінну для слова.
Для цього нам потрібно вибрати "дамп 2", щоб коли ви перейдете до карти пам'яті, вона відображалася в дампі 2. І ми переходимо до сегменту BSS, двічі клацаємо
і шукаємо порожнє місце для зберігання нашого слова, щоб ми могли його використати.
Тож скопіюй адресу.
Скопіюйте цю адресу: 405010.
І це буде нашим словом.
А потім для %s - ще один специфікатор формату.
Тож ми розмістимо її тут, адресу
для цього.
Тож %s - поверніться до даних.
Знайдіть порожнє місце ось тут і бінарне редагування
і просто введіть %s, натисніть "ОК".
А потім скопіюйте цю адресу.
І покладіть його сюди.
Отже, тепер у нас є параметри для scanf, і все готово.
Далі нам потрібно оголосити довжину нашого рядка.
Слово - це те ж саме.
Ось цей.
Ця адреса не змінилася.
Тож ми просто вставляємо його сюди.
Далі нам потрібно створити цей рядок.
Отже, ми переходимо до даних 1 і знаходимо порожнє місце, і можемо вставити туди наш рядок.
Виділяємо його і бінарно редагуємо, а під текстовою клавішею вводимо "%s має %d" "символи.
А
потім з'являється новий персонаж рядка.
Отже, ми переходимо до цього байту і вводимо 0A гекс для нового рядка.
Натисніть "ОК" і просто перевірте, чи все правильно.
Але 0A - тож тут весь рядок перейде на наступний рядок.
Тож ми це зробили.
Отже, ми копіюємо адресу цього рядка, яка знаходиться тут, копіюємо адресу і вставляємо її під рядком, щоб можна було
легко на неї посилатися.
Тоді слово - це змінна, тому ми можемо скопіювати його.
Це той самий і вставте сюди.
А для num_chars ми не оголосили іншу змінну для зберігання цілого числа для string length, тому
string length поверне результат, а нам потрібно зберегти результат у num_chars.
Отже, num_chars також є BSS-сегментом, тому ми можемо використати ще один сегмент.
Може, цей.
Клацніть правою кнопкою миші і скопіюйте цю адресу сюди, а потім
вставте
сюди, num_ символів. Отже, ми готові до кодування. Нам потрібно отримати адресу функції.
Отже, переходимо до таблиць переходів, шукаємо функцію printf, яка знаходиться тут. Клацніть правою кнопкою миші, скопіюйте цю адресу
функції printf, вставте її сюди. Сканф.
Прокрутіть вгору і знайдіть scanf.
Клацніть правою
кнопкою миші, скопіюйте цю адресу, вставте її сюди, а потім перевірте довжину рядка.
Це довжина рядка, скопіюйте адресу і вставте сюди адресу довжини рядка.
Тепер ми готові повернутися до IP і почати кодування.
Отже, спочатку треба натиснути на цю струну.
Цей рядок є адресою цього рядка.
Тож просто натисни туди.
Отже, у нас є рядок: "Введіть
слово. Далі нам потрібно викликати
функцію друку, а саме: викликати printf. Отже, адреса функції printf буде
такою.
Потім нам потрібно зробити сканф.
Отже, це параметри для scanf, а це функція scanf.
Тож поширюй інформацію.
Отже, слово за адресою.
Отже, ми отримуємо це і переносимо адресу за словом до стеку.
Потім ми натискаємо специфікатор формату, а саме цей.
Скопіюй адресу.
Далі нам потрібно викликати функцію scanf.
Отже, скопіюємо адресу функції.
І зателефонуй сюди.
І у нас є функція сканування.
Отже, це два параметри для сканфайлу.
Тепер нам потрібно зробити деякі обчислення, використовуючи довжину рядка.
Отже, довжина рядка потребує цього слова-параметру.
Отже, ми копіюємо адресу дослівно, яка знаходиться тут.
І ми штовхаємо його до штабеля.
І далі ми викликаємо функцію довжини рядка.
Тож візьміть адресу і зателефонуйте сюди.
Отже, це виклик функції довжини рядка, а це параметр довжини рядка.
Далі нам потрібно - після виклику string length підрахувати кількість символів
у слові і зберегти їх у -.
Потім потрібно зберегти - у змінну num_chars.
Тож давайте зробимо це зараз.
Отже, MOV, слово вказівник.
Адреса num_chars знаходиться тут, тому копіюємо адресу.
І покладіть його сюди, а потім ззаду.
Отже, ми зберігаємо значення в - за адресою тут.
Потім нам потрібно виконати останню операцію, а саме printf.
Отже, є три параметри:
один, два, три.
Тому ми штовхаємо їх у зворотному порядку справа наліво.
Отже, спочатку цей.
Тож давайте штовхати.
Гаразд, ми
маємо вилучити посилання.
Отже, розіменовуємо адресу num_char.
Отже, num_char тут.
Просто скопіюйте цю адресу та вставте її сюди.
Далі буде проштовхування
слова. Слово є рядком, тому не потрібно розіменовувати рядки.
Зрозумів.
І натискаємо адресу
рядка, слова.
А далі йде ще один рядок, який є специфікатором формату, а саме цей.
Отже, ось ця адреса.
І ми штовхаємо його до штабеля.
Отже, це теж рядок.
І нарешті, нам потрібно викликати printf, тому отримайте адресу printf тут, скопіюйте адресу функції printf
і викличте її тут.
І ми закінчили.
Просто для перевірки: ви натискаєте на це "Введіть слово", викликаєте printf, щоб вивести його на екран.
Потім ви натискаєте параметри для сканування, і ви зчитуєте дані, введені користувачем, і зберігаєте їх за цією адресою.
А потім вам потрібно викликати string length, і ви виштовхуєте параметр довжини рядка в стек, і викликаєте string
length.
String length збереже свій результат в -, а вам потрібно скопіювати значення в - в пам'ять.
Отже, ви використовуєте цю інструкцію MOV.
Потім потрібно викликати printf для виведення результату.
Отже, вам потрібно ввести три параметри для printf тут.
Цей - розіменування значення за цією адресою, яке було скопійоване з -.
Отже, це ціле значення.
Вам потрібно розіменовувати його, а потім виштовхувати рядок до стеку, яким є цей рядок %s.
Введено початкове слово.
Потім ви натискаєте специфікатор формату і викликаєте printf, щоб показати результат.
Тож тепер ви можете запустити його. Спочатку поставте точку зупинки і запустіть її.
І це ваш результат.
Відійди.
Він виштовхне цей рядок до стеку.
Давай переступимо.
А на стеку рядок: "Введіть
слово. Далі printf використовуватиме
цей параметр.
Переступимо, і printf надрукує
"Введіть слово.
Далі
ми виштовхнемо параметри сканування до стеку.
Тож давай переступимо.
Отже, це адреса пам'яті для слова.
Подивіться на звалище 2. Дамп 2 - 67405010.
Це місце, де слово буде зберігатися.
Тож давай переступимо.
І він виштовхнув його до стеку, а також виштовхнув %s, специфікатор формату, до стеку.
Отже, це два параметри для scanf, які вже є у стеку.
Далі збираюся викликати scanf, і спостерігати, що відбувається з державою.
Коли ми переступаємо, сканування змінюється на біг.
Отже, ми натискаємо сюди, і там з'являється підказка.
І ви вводите наше
слово "яблуко", наприклад. Коли ми натискаємо клавішу Enter, він повертається з режиму виконання в режим паузи, і ми знову опиняємося в нашому відладчику.
А тепер нам потрібно порахувати довжину рядка - кількість символів у цьому слові.
Отже, нам потрібно спочатку виштовхнути його до стеку, щоб програма довжини рядка могла використовувати його як параметр.
Тож давайте переступимо, і ви побачите, що слово, рядок "яблуко", вже лежить на стопці. А тепер довжина рядка використає це для
підрахунку кількості символів і збереже результат.
Тож дивись... Переступи, - повертається п'ятірка.
Потім функція повертає значення довжини рядка функції п'ять і зберігає його в -.
Отже, він підрахував кількість символів у слові "Apple", яка дорівнює п'яти.
Тепер ми збережемо цей результат у пам'яті за адресою 405030, яка знаходиться тут.
Дивіться, що відбувається, коли я переступаю через цю інструкцію MOV. Тож там зберігається п'ять.
Отже, ця п'ятірка зберігається з - в пам'ять.
Далі ми викличемо printf, але спочатку нам потрібно ввести три параметри для printf.
Отже, три параметри printf - це і є ці три параметри. Нам потрібно натиснути у зворотному порядку: num_chars, слово
і специфікатор формату.
Отже, це num_chars.
Отже, на num_char потрібно розіменовувати посилання, оскільки це адреса. Нам потрібно значення,
яке зберігається за цією адресою, а саме п'ять.
Отже, нам потрібно розіменовувати посилання і виштовхувати його до стеку.
Тож якщо бачимо п'ять, штовхаємо до стопки.
Давайте переступимо через це.
І тут, дійсно, ви бачите п'ять у стопці. Тоді він виштовхне рядок до стеку, тому
що це рядок.
Тож давайте переступимо, і ви побачите, що рядок "яблуко" лежить на стопці. А далі ми виштовхнемо цей специфікатор формату
до стеку.
Переступаємо, і специфікатор формату опиняється у стеку.
І, нарешті, він викличе функцію друку.
Функція друку використовуватиме ці три параметри: один, два, три, один, два, три,
тобто посилатиметься на ці три параметри: один, два, три.
І виведе повідомлення на екран.
Давайте переступимо через це.
І там сказано: "Apple має п'ять символів", тож ось як ми можемо розв'язати цю вправу.
Отже, давайте збережемо цей файл: patch і patch file, і дамо йому ім'я.
26, 26, вправа на довжину
тире.
Ось так.
Гаразд.
Ось вам порада.
Переконайтеся, що слово, яке ви вводите, не містить пробілів.
Це має бути одне слово.
Якщо ви напишете "Hello", пробіл, а потім "world" - "Hello world"
- scanf прочитає тільки перше слово, тому що scanf припинить читання після того, як побачить пробіл.
Отже, якщо ви наберете "Hello world", це не збереже "world" в кінці.
Врятує лише "привіт. У цьому й полягає
обмеження сканфу.
Якщо ви хочете прочитати "Hello World", вам потрібно скористатися іншою функцією, яка називається fgets.
Але fgets не імпортується у цю таблицю переходів, тому я її не використовував.
Отже, ось як ви вирішуєте цю вправу.
Дякуємо за перегляд.