Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Языки и методы программирования - лекция-6: выз...

Anton
December 08, 2024

Языки и методы программирования - лекция-6: вызов подпрограмм, передача параметров через стек

Лекция курса "Языки и методы программирования"
Лекция-6: вызов подпрограмм, передача параметров через стек
- Повторное использование одних и тех же участков кода
- Библиотеки подпрограмм, повышение производительности труда в области разработки программ
- Реализация механизма: ветвление с сохранением адреса возврата на примере архитектуры MIPS32
- Прыжок с сохранением адреса возврата jal (jump and link)
- Переход по адресу в регистре jr (jump register)
- Передача аргументов, возвращаемое значение
- Разделение логики и данных
- Структура данных: стек
- Сегменты памяти программы
- Стек (сегмент памяти)
- Реализация (на примере архитектуры MIPS32)
- Пример: выполнение программы с передачей параметров в подпрограмму через стек на ассемблере MIPS32
- Возвращение результата подпрограммы через регистры
- Задания для самостоятельной работы

Anton

December 08, 2024
Tweet

More Decks by Anton

Other Decks in Education

Transcript

  1. А бывают ситуации, когда • один и тот же код

    нужно использовать из разных частей приложения • В жизни часто бывает, что решение одной и той же задачи требуется в разных частях программы • примеров масса: математические формулы, ввод/вывод, операции с устройствами, сетью и т. п.
  2. • Сейчас сложно вообще представить программу, которая бы не вызывала

    какие-то участки кода повторно: • она полагается на внешние программные библиотеки, стандартные вызовы платформы (Java, Python), вызовы операционной системы и т.п.
  3. • Это миллионы человеко-часов интеллектуального труда, воплощенные в программных продуктах

    • Колоссальная экономия времени на разработку — повышение производительности труда в процессе разработки • Даже если речь идет о собственном коде внутри одного проекта
  4. • Для воспроизводства материальных продуктов потребления требуется раз за разом

    тратить известное количество труда • Идея открывается / изобретается / формулируется один раз • После этого она воплощается в жизнь — приносит экономический эффект через труд других людей • Но в этом процессе ученый / инженер / изобретатель уже не занят
  5. • С механизмом подпрограмм программист не переписывает раз за разом

    одну и ту же программу • Он пишет новую программу, опирающуюся на код старой программы
  6. • The report set out the general principles of coding,

    described the authors' system of flow diagramming, programmed a number of typical scientific and engineering problems, and discussed a programming methodology built around the use of libraries of subroutines. William Aspray, «John von Neumann and the origins of modern computing»
  7. • The ENIAC, the Harvard Mark I, IBM punched-card machines,

    and essentially all other earlier calculating devices employed a fixed addressing system. Each time any one of these machines was programmed, the program had to be coded anew, even if the new program shared many of the same steps with an earlier one. The incorporation of variable addressing on the institute computer made the programming task more efficient. William Aspray, «John von Neumann and the origins of modern computing»
  8. • The incorporation of variable addressing on the institute computer

    made the programming task more efficient. Frequently used programs, such as routines for producing square roots or trigonometric functions, could be stored on an external storage medium in a subprogram library and called into use by mounting the appropriate tape and assigning parameters in such a way that they agreed with the main body of the program. William Aspray, «John von Neumann and the origins of modern computing»
  9. • The authors anticipated that the use of subroutine libraries

    would provide a methodology for the effective use of the computer: 'The importance of being able to do this [write subroutines rather than recode each time] is very great. It is likely to have a decisive influence on the ease and the efficiency with which a computing automat of the type that we contemplate will be operable. This possibility should, more than anything else, remove a bottleneck at the preparing, setting up, and coding of problems, which might otherwise be quite dangerous. William Aspray, «John von Neumann and the origins of modern computing»
  10. • Provided we know the series of operations to be

    gone through, that is sufficient. • Вполне достаточно знать последовательность операций, которые следует выполнить. Ада Августа Лавлейс, 1843
  11. Технически уже понятно: • Мы можем в нужном месте прыгнуть

    по известному адресу, там будет находиться известная последовательность операций • Если мы будем прыгать на это место из разных мест программы, то эта последовательность операций (участок программы — подпрограмма) будет выполняться многократно • Но здесь возникает дополнительный нюанс: мы еще будем должны каким-то образом вернуться • Для этого нам нужен не только механизм самого прыжка, • но и механизм возврата в то место, откуда прыгнули
  12. Было бы логично • Каким-то образом сохранить адрес, с которого

    осуществлен прыжок • Так, чтобы потом к нему вернуться из того места, куда улетели • В том месте, куда улетели, в конце должен быть обратный прыжок
  13. Пример • По хорошей традиции начнем с MIPS32 ASM •

    Для этого уже есть готовые команды: • Прыжок с сохранением адреса возврата (сохраняется в регистре) • Обратный прыжок — безусловный прыжок по адресу из регистра (удобнее, чем тот прыжок, который у нас уже был)
  14. Прыжок с сохранением адреса возврата • jal (jump and link)

    — безусловный переход с возвратом jal addr • addr — адрес прыжка - (в коде asm — метка нужной строчки), - (в двоичном коде: смещение относительно текущей инструкции) Действие: • Сохранение в регистре $ra (return address) адрес инструкции, следующей за текущей • Переход на адрес addr (установить новое значение pc — program counter)
  15. Переход по адресу в регистре • jr (jump register) —

    безусловный переход по регистру jr rs • rs — регистр, содержащий абсолютный адрес перехода Действие: • Осуществить переход по адресу из регистра (установить новое значение pc — program counter)
  16. j main count_3: addi $s1, $s1, 3 # возвращаемся (return)

    jr $ra count_5: addi $s1, $s1, 5 # возвращаемся (return) jr $ra main: jal count_5 jal count_3 jal count_5 sw $s1, 8 ($0)
  17. Замечания • Использование регистра $ra для сохранения адреса возврата из

    процедуры — соглашение для архитектуры MIPS32, • Дело не только в рекомендациях, именно в него автоматически возвращает значение перед прыжком команда jal • (с обычной командой j — jump вы сможете прыгнуть, но не сможете сохранить точку, откуда прыгнули) • На других архитектурах могут быть другие механизмы возврата из процедуры, но суть действия не поменяется — адрес возврата так или иначе будет где-то сохранен
  18. Параметры • Без параметров функция (подпрограмма) будет выполнять одно и

    то же действие • Для математики это обычно не очень полезно, хотя бывает всякое • Если речь не о математических вычислениях, очень часто нужны функции без параметров (например, вывести текущее состояние системы на экран, проверить значение известного датчика и т. п.) • Другие источники вариативности: глобальные переменные, регистры (на ассемблере), ввод пользователя, файл, сеть, рандом и т. п. — их сейчас не рассматриваем
  19. Возвращаемое значение • Для математики: результат вычисления формулы • В

    остальных случаях: статус возврата (успешно / не успешно), код возврата, прочитанное значение и т. п. • Другие способы оставить результат: глобальные переменные, запись в регистры (на ассемблере), вывод на экран, в файл, в сеть, перезапись параметров, переданных по адресу, и т. п. — их сейчас не рассматриваем
  20. These cards, however, have nothing to do with the regulation

    of the particular numerical data. They merely determine the operations to be effected, which operations may of course be performed on an infinite variety of particular numerical values, and do not bring out any definite numerical results unless the numerical data of the problem have been impressed on the requisite portions of the train of mechanism. Ada A. Lovelace, 1843
  21. Эти карточки, тем не менее, не имеют отношения к конкретным

    численным данным. Они только определяют операции для осуществления, эти операции могут быть выполнены на бесконечном разнообразии конкретных численных значений и не дают конкретный численный результат до тех пор, пока не будут предоставлены численные данные задачи на соответствующих частях передачи механизма. Ада Августа Лавлейс, 1843
  22. • Без возможности передавать функциям (подпрограммам) параметры и получать обратно

    результаты вычислений, • Наши возможности в выделении повторяющихся участков кода в подпрограммы были бы весьма ограничены • Это бы ограничило наши возможности в разделении логики и данных • Мы бы не могли «выделять набор операций, а потом выполнять его на бесконечном разнообразии численных значений, получая таким образом необходимый нам в том или ином случае конкретный результат» (А. А. Л.)
  23. • Мы бы не могли копить наши знания о логике

    в подпрограммах, применяя их к конкретному набору данных в нужный момент • И у нас бы не было в распоряжении миллионов человеко-часов, накопленных в программах и библиотеках, доступных сейчас любому разработчику программного обеспечения
  24. Вообще говоря, дело не только в вычислителях • Разделение логики

    и данных — типичное представление математических знаний • Логика — это универсальная формула, составляется один раз и дальше без изменений используется неограниченное количество раз (некоторые формулы не меняются столетиями) • Для решения практической задачи мы подставляем в формулу конкретные численные значения (величины)
  25. • Предмет математики — величина Г. Гегель • In fact

    the engine may be described as being the material expression of any indefinite function of any degree of generality and complexity • [Аналитическая] машина — это материальное воплощение [математической] функции любой степени общности и сложности Ада Августа Лавлейс, 1843
  26. • Нет ничего удивительного в том, что компьютерные программы могут

    напоминать математические формулы в классическом математическом представлении • В сущности, это и есть математические формулы, просто язык их записи специфичен для автоматических вычислителей
  27. Но для этого сначала • Познакомимся со специальным способом организации

    памяти: • выделения участков памяти для работы и освобождения их для повторного использования • Сегмент памяти данных с особыми правилами обращения с ней (модель поведения) — «Стек»
  28. Допустим, у нас есть последовательность однотипных элементов • Если их

    упорядочить, выстроив один за другим (можно пронумеровать, выстроив натуральный ряд), • У нас получится массив элементов или список элементов — сейчас это не суть • Дальше встаёт вопрос, как мы будем элементы в эту последовательность добавлять и извлекать • Можно произвольным образом (по адресу), а можно ввести некоторое правило
  29. Очередь (Queue) • Не столько структура, сколько поведение • FIFO:

    first-in first-out • Поведение можно реализовать поверх массива или списка Операции: • Add (enqueue) — поместить элемент в очередь • Remove (dequeue) — извлечь элемент из очереди
  30. Жизненные ситуации • Живая очередь в магазине • Электронная очередь

    • Конвейер на производстве • Строительство юнитов на базе (RTS) • Очередь событий с устройств ввода (нажатие кнопок клавиатуры и клики мышки) • «Final destination» («Пункт назначения», 2000)
  31. Стек (Stack) • Не столько структура, сколько поведение • LIFO:

    last-in first-out • Поведение можно реализовать поверх массива или списка Операции: • Push — положить элемент на вершину стека • Pop — забрать элемент с вершины стека
  32. Жизненные ситуации • Стопка тетрадей на проверку • Стопка грязных

    тарелок • Магазин в пистолете • «It follows» («Оно», 2014)
  33. Стек (сегмент памяти) • Область памяти, имеющая определенную логическую структуру

    • Часть этой памяти зарезервирована под размещение параметров и локальных переменных функций (иногда для возвращаемых значений или даже адреса возврата из процедуры) • Другая часть помечена как неиспользуемая • Память резервируется в процессе вызова функции, освобождается после того, как функция выполнена • Блок памяти, зарезервированный под отдельную функцию, — кадр стека
  34. Реализация (на примере архитектуры MIPS32) • Указатель стека — регистр

    $sp (stack pointer), вершина стека • Определяет границу: «используемая — не используемая память»
  35. • Содержит наименьший адрес памяти, граничащий с максимальным адресом из

    неиспользуемой области стека • (это будет минимальный адрес из выделенных ячеек или адрес за правой границей стека, если на стеке ничего не выделено) • Обычно: начинается с адреса, следующего за максимально доступным адресом памяти программы (с противоположной стороны ленты от данных, инструкций и кучи)
  36. • Уменьшается при вызове функции (стек растет) • Увеличивается (откатывается)

    при завершении работы функции (стек сжимается) • Переполнение стека (stack overflow) — если вызывать функции одну из одной достаточное количество раз
  37. Пример: программа • Принимает из памяти значения по адресу 0x0

    (a) и 0x4 (b) • Вычисляет результат формулы: (a - b) * 2 • Вычисление оформлено в виде подпрограммы, принимающей значения параметров a и b через стек и возвращающей значение через регистр $v0 • Результат вычисления записывает в память по адресу 0x8
  38. Замечания • В архитектуре MIPS32 для передачи первых 4-х параметров

    принято использовать регистры $a0 - $a3, • Остальные параметры — через стек • Рекомендациям принято следовать, но технически никто не запретит сделать по-своему • Возвращаемые значения — регистры $v0 - $v1 • (оба регистра могут быть задействованы в том случае, если нужно вернуть, например, 64-битное значение) • Значения так же можно возвращать, например, через стек • Это зависит от архитектуры, компилятора (если у вас язык высокого уровня) и ваших потребностей (например, если вам нужно вернуть значение больше, чем уместит регистр, и вы при этом не хотите использовать динамическую память).
  39. Замечания • В приведенном примере мы сначала добавили в стек

    один элемент (кадр стека), а потом его же и удалили и на этом закончили • Мы увидели механизм передачи параметров в процедуру через работу со стеком на низком уровне, но потенциал стека как динамической структуры в полной мере не раскрыли • Более интересные примеры — когда мы не просто вызываем функцию, а вызываем функцию из другой функции, потом оттуда еще одну функцию и так далее • Эти сценарии мы рассмотрим подробнее на будущих занятиях
  40. Замечание • Подпрограмма, функция, процедура, метод (в ООП) — обычно

    взаимозаменяемые термины, вполне можно использовать как синонимы • Иногда более строго определяют функцию как подпрограмму, возвращающую значение, • а процедуру, как подпрограмму, не возвращающую значение • Метод — это функция, определенная для объекта (в объектно- ориентированном программировании) • На практике они легко превращаются одна в другую • За строгостью терминов конкретно вот этих не будем следить
  41. Задания — самостоятельно • Запустить приведенный в лекции код в

    среде MARS MIPS • Изменить реализацию игры «угадай сумму» так, чтобы код, проверяющий проигрыш или выигрыш, был оформлен в виде подпрограммы, принимающей два параметра — слагаемые, и возвращающей результат — количество баллов (1 — не угадал, 100 — угадал). Варианты передачи параметров: через стек или через регистры. • Бонус: написать программу, вычисляющую дискриминант квадратного уравнения по формуле (потребуется дополнительная команда умножения — mul), формула вычисления должна быть оформлена в виде процедуры