Привіт і ласкаво просимо назад.
У цій лекції я розповім вам про важливість збереження стану реєстрів за допомогою push
and pop.
Чому важливо зберігати дані регістру, виштовхуючи їх у стек перед викликом, а потім відновлювати пізніше,
витягуючи їх після завершення виклику функції?
В асемблерному програмуванні, коли викликається функція або підпрограма (підпрограма - це просто
інша назва функції), зазвичай використовуються ті самі регістри, що й у функції, яка її викликала.
Оскільки регістри є спільним ресурсом для всіх частин програми, якщо викликана функція змінює
значення регістру, вона може ненавмисно вплинути на інші функції програми, які покладаються на ті самі
регістри.
Ось чому важливо зберігати значення реєстру перед викликом і відновлювати їх після нього.
Давайте подивимося на цю програму тут.
Ця програма робить виклик функції у цьому рядку.
І перед викликом ви зберігаєте регістр, тому що він використовується функцією.
А потім ви робите виклик функції.
А після дзвінка ви знову відкриваєте регістр, так що дія натискання на регістр зберігає початкове
значення -, яке дорівнює п'яти.
А після виклику ви повертаєте значення five назад у регістр, витягаючи його зі стеку.
Після цього програма
- головна програма - буде використовувати значення в регістрі - для додавання за допомогою -.
Отже, у цьому прикладі ви бачите, що функція використовує регістр - register. Він модифікує його, додаючи
до нього три, а потім зберігає у - - після чого зберігається.
Він переміщує значення - в - і повертається назад.
Отже - матимемо повернення виклику функції - значення, що повертається при виклику функції.
Отже, в головній функції, коли вона повертається до головної функції, вона бере результат виклику функції,
який зберігається в -, і додає до нього -.
Отже, якщо - не відновити до п'яти, то ви отримаєте неправильне значення, оскільки - було б змінено
самою функцією.
Ось чому важливо вискочити - і підштовхнути - до дзвінка.
Тому в цьому випадку, якщо ви вказали значення D - візьміть інший приклад.
Той самий приклад, але цього разу ми не штовхаємо і не вискакуємо.
Якщо ви запустите ту ж саму програму без натискання, ви побачите, що кінцеве
значення - тут буде 10.
Отже, це буде відрізнятися від наведеного тут прикладу.
Як бачите, просто не зберігши значення в -, ви отримаєте інший результат.
Отже, давайте спробуємо запустити це у x64dbg і подивимося, як це відбувається у реальному часі.
Отже, ось ваші 67 - збережені -.
Ви також можете створити такий самий файл.
Просто введіть весь цей код тут, який, власне, і є тим кодом, який ви бачите тут.
Ось цей ти бачиш тут.
А потім для функції я поміщаю функцію в печеру коду.
Отже, ось ця печера коду.
І ось тут я додаю функцію - і -, і рух, і -.
Отже, це сама функція, яка йде звідси.
Після цього я поставив точку зупинки в основній програмі.
Основне - це те, де ви знаходите викликувач функції.
Отже, це і є виклик функції тут.
Тож я ставлю тут точку зупинки, а потім запускаю її - і вона зупиняється.
Крок вперед, крок вперед, крок вперед на поклик.
А тепер ми підемо рядок за рядком.
Тоді дзвінок передзвонить.
Тепер функція повернеться.
Тож давайте переступимо і повернемося на головну, а потім переступимо.
А тепер вона бере результат
виклику функції - - і додає його до -, і тоді результат - це D, як і було сказано тут.
Спробуємо зробити це на іншому прикладі.
Цього разу ми видалимо цей push і цей pop.
Тому я написав ще одну програму.
Давай припинимо це.
Інша програма - 68, і я називаю її 68 - без збереження.
Тож вам варто зробити те ж саме.
Просто створіть цю програму і збережіть її під цією назвою.
А тепер поставте точку зупинки, як зазвичай, ось тут.
Точка зупинки, перемикання, перехід до точки зупинки.
Відійди.
А тепер зверніть
увагу, що там, де раніше був push - -, з'явився ноп, а тут - ще один ноп, де раніше був pop-. Тож тепер я збираюся зробити крок на виклик - крок на виклик - і потім переступати через кожну
лінію, поки він не повернеться.
Поверніться на головну сторінку, а зараз ми перейдемо до наступного рядка.
Це додасть - до -.
- результат виклику функції.
Тож переступайте, і ви побачите, що це дає інший результат.
У ньому 10.
Зверніть увагу, що раніше це було D, а тепер ми отримуємо 10.
Тож це дуже важлива
демонстрація того, що якщо ви не збережете стан реєстру,
це матиме непередбачувані результати - результати, яких ви не очікували.
Отже, якщо ваша функція буде використовувати
регістри - загальні регістри,
такі як -, -, -, -, - і так далі - важливо виштовхнути їх у стек перед викликом функції.
Гаразд.
Ще один момент, на який я хотів би звернути увагу, це те, що порядок потуг має велике значення.
Тож давайте візьмемо приклад.
У вас є три регістри - в -, у вас є
значення три. - має значення сім, - має значення дев'ять.
Тепер, якщо ви натискали "натиснути", потім "натиснути" і "натиснути", то коли ви витягнете його пізніше,
ви повинні витягти його у зворотному порядку.
Чому?
Тому що концепція стеку - це "останнім прийшов, першим пішов".
Тож, хто останнім увійде, той першим вийде.
Це як концепція млинця.
Млинець - це місце, куди ви кладете млинець знизу вгору.
Тому, коли ви берете млинець,
ви берете його зверху, а не знизу.
Так само і тут.
Отже, ви натискаєте, натискаєте, натискаєте,
натискаєте, а потім робите все, що хочете, виконуючи свою функцію або використовуючи ці регістри.
І коли ви закінчите, вам слід вискочити в зворотному порядку.
Отже, ви повинні спочатку натиснути pop -, потім pop -, а потім pop -.
Якщо ви переплутаєте цей порядок, то в результаті поміняєте
місцями значення між цими регістрами, а це, можливо, не той ефект, який ви хотіли отримати.
Тож про це слід пам'ятати щоразу, коли ви використовуєте push і pop - завжди натискайте і виштовхуйте
в зворотному порядку.
Тож давайте зробимо симуляцію.
Тепер штовхаємо - - так - штовхається в кінець стопки.
Штовхаємо - - - тепер йде зверху сюди.
Натискаємо - - - тепер піде прямо нагору.
Гаразд, тепер ви закінчили з трьома поштовхами.
Тепер, коли ви хочете вискочити, ви повинні вискочити - першим.
Отже, ви вставляєте цей в -, потім вставляєте в - - цей.
Потім ви потрапляєте
в - - цей.
Він завжди буде вискакувати, що б не було на вершині стопки.
Потім ви
отримуєте назад початкове значення: 3, 7, 9. Ось так ви можете візуалізувати важливість правильної послідовності проштовхування і виштовхування.
На цьому відео все.
Дякуємо за перегляд.