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

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

Avatar for Anton Anton
December 08, 2024

Языки и методы программирования - лекция-3: архитектура компьютера и программы на языках высокого уровня

Лекция курса "Языки и методы программирования"
Лекция-3: архитектура компьютера и программы на языках высокого уровня
- Коммутационные панели (коммутационные доски, commutation plugboard)
- "Программирование" ЭНИАК перенастройкой коммутационных панелей
- Повышение производительности труда в области перенастройки компьютера под задачу: концепция хранимой программы
- Архитектура Джона фон Неймана
- Концепция хранимой программы
- Повышение производительности труда в области создания (разработки) программы: язык ассемблера, компиляторы, языки программирования высокого уровня
- Машинный код
- Язык ассемблера
- Программа в памяти
- Языки программирования высокого уровня
- Компилятор
- Язык Си: переменные, размещение переменных в памяти, ассемблерный код для инструкций языка Си, выполнение простой программы по шагам
- Просмотр ассеблерного кода программы на Си в отладчике Qt Creator
- Инструменты кросс-компиляции программы на Си для архитектуры MIPS32, просмотр ассемблерного кода исполняемого файла с objdump
- Итоги
- Задания для самостоятельной работы

Avatar for Anton

Anton

December 08, 2024
Tweet

More Decks by Anton

Other Decks in Education

Transcript

  1. Коммутационные панели • Электромеханические счетные машины Германа Холлерита в начале

    20-го века умели считать статистические показатели на больших объемах данных, записанных на перфокартах • Логика счета определялась специальной электрической схемой: для разных показателей требовалось составить разные комбинации электромеханических переключателей (реле) • Для часто используемых показателей такую схему можно было спаять целиком и установить в машину в качестве готовой составной детали • Но для ситуаций, когда логику счета требовалось менять относительно часто, такой подход оказался слишком негибким • В следующих версиях машин для удобства перенастройки схемы стали использовать т. н. коммутационные панели (commutation plugboard)
  2. • Развитие и распространение — в статистических перфокартных машинах IBM

    (и конкурирующих производителей) • Но не только • Один из первых электронных вычислителей общего назначения ENIAC использовал аналогичный подход
  3. ENIAC (1945) • en.wikipedia.org/wiki/ENIAC • Electronic Numerical Integrator and Computer

    • Первый программируемый электронный цифровой компьютер общего назначения • Общего назначения: полон по Тьюрингу • Построен: 1945 год • Элементная база: электронные вакуумные лампы и реле
  4. ENIAC (1945) • Процесс программирования компьютера выглядел как процесс переподключения

    проводов • (уже есть программа, но называть процесс программирования вычислителя «внесением программы в компьютер» не вполне корректно — скорее здесь процесс частичной пересборки компьютера под программу) • Т.о. программа здесь — это алгоритм, определяющий логику вычислений, который может быть переведен на язык электрической схемы • Финальная форма программы — электрическая схема • Компьютер здесь выступает как своеобразный электрический конструктор (полуфабрикат), который можно пересобрать по схеме
  5. • Процесс перенастройки вычислителя под программу был довольно трудоёмким и

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

    схему подключения проводов вычислителя явным образом отделен от процесса перенастройки компьютера под выполнение программы • Процесс написания программы — труд в чистом виде интеллектуальный • Процесс перенастройки компьютера по схеме — труд в чистом виде физический • В процессе перенастройки просто так (как в любимой IDE) провода туда-сюда не попереключаешь, чтобы посмотреть, как та или иная комбинация подключений повлияет на то, как будет работать алгоритм — программу писали и «отлаживали» в голове и на бумаге задолго до запуска
  7. Архитектура Джона фон Неймана • Сложность перенастройки ENIAC для каждой

    новой задачи являлась существенным и заметным ограничением, которое в следующих проектах вычислителей решили устранить • Над одним из проектов работал Джон фон Нейман • Он пришел в команду разработчиков ENIAC на поздней стадии проекта в качестве консультанта, быстро вник в суть дел, потом внутри команды произошел конфликт, • Джон фон Нейман продолжил работу над проектом нового универсального вычислителя в другом месте с новой командой, в качестве руководителя
  8. • К реализации проекта подошли академически: значительное внимание уделили проработке

    теоретического фундамента и этапу проектирования • В рамках этой работы было опубликовано несколько отчетов, в которых были сформулированы базовые принципы, которые должны быть реализованы в проекте вычислителя • Эти принципы были хорошо приняты научным и инженерным сообществом, легли в основу практически всех последующих проектов вычислительной техники • Сохранились в истории под именем Джона фон Неймана как «фоннеймановская архитектура» или «архитектура Джона фон Неймана» (хотя автором идей и документа был не он один) • В соответствии с принципиальной позицией Джона фон Неймана они стали общедоступными — не были запатентованы
  9. Концепция хранимой программы • Среди прочего, в отчетах были сформулированы

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

    памяти вычислителя, будучи логически представлены нулями и единицами, • Фактически представляют собой закрытые и открытые транзисторы, которые выстраивают электрические цепочки связей
  11. • В зависимости от того, как расположены нули и единицы

    в машинном коде текущей инструкции, внутри вычислителя будут активированы те или иные электрические цепи, в той или иной последовательности соединяющие между собой аппаратные вычислительные блоки • Труд по переконфигурированию ЭВМ переподключением проводов теперь происходит в автоматическом режиме • Коммутационная панель больше не нужна
  12. • Реализация концепции хранимой программы позволила радикально уменьшить время перенастройки

    компьютера при смене рабочей программы • (повысить производительность труда оператора ЭВМ) • Вместо ручного переподключения проводов на коммутационной панели, программу можно было сохранить на внешний носитель (перфокарту или магнитную ленту), • А потом загрузить на выполнение во внутреннюю память вычислителя («загрузить программу в компьютер» — теперь так говорить вполне корректно) — так же, как это уже делали с данными
  13. • Труд оператора теперь: подключить внешний носитель к вычислителю и

    инициировать процесс загрузки машинного кода программы в память для выполнения • В современном исполнении: набрать команду в терминале, нажать кнопку «запустить» в среде разработки, два раза кликнуть на исполняемом файле, нажать иконку на экране смартфона, кликнуть на ссылку в браузере и т. п. • Процесс «перенастройки» вычислителя для выполнения новой программы (загрузка программы в память) настолько слился с процессом повседневной эксплуатации вычислителя, что мы его не замечаем
  14. • Труд системного администратора (оператора ЭВМ, отвечающего за загрузку и

    работу программного обеспечения на аппаратном обеспечении) по форме сложно отличить от труда разработчика программного обеспечения (оба сидят за компьютером, нажимают кнопки, запускают программы) • По содержанию тоже есть множество пересечений: системный администратор может писать скрипты или программы, а разработчик программного обеспечения сам регулярно запускает какие-то программы и т. п.
  15. Существенная разница: • Продукт труда разработчика ПО — программное обеспечение,

    т. е. идея • Продукт труда системного администратора (оператор ЭВМ, devOps) — могут быть услуги или материальные блага, создаваемые посредством обслуживаемого им аппаратного обеспечения
  16. • Однако, с производительностью труда по загрузке ПО на вычислитель

    теперь всё более- менее понятно • Рассмотрим теперь ближе труд по созданию программного обеспечения: что он из себя представляет, какие есть возможности сократить затраты времени на него
  17. Машинный код • Первое время набивали вручную на перфокартах •

    Но мыслить «нулями и единицами» человеку проблематично • Так или иначе, у машинного кода имелось представление, читаемое человеком
  18. Язык ассемблера • Символьное представление полей машинной инструкции, которое может

    читать и писать человек • Взаимнооднозначное соответствие • Но некоторые детали уже скрываются за удобным синтаксисом (например, из ассемблерной записи может быть не вполне очевиден максимальный размер численных параметров) • По большей части: одна инструкция в машинном коде — одна строка в программе на ассемблере • (но не всегда: появляются т. н. мета-команды, облегчающие разработку)
  19. Язык ассемблера • Т.к. машинный код представлен в памяти в

    виде чисел • и код программы на ассемблере тоже может быть представлен в виде чисел (кодированный текст) • А компьютер у нас — универсальный вычислитель, который может путем формально-логических и арифметических преобразований превращать одни числа в другие, • А правила соответствия между числами машинного кода и числами, представляющими программу на ассемблере, с точки зрения формальной логики однозначны и довольно просты, • Можно написать такую компьютерную программу, которая автоматически превратит текстовое представление программы на языке ассемблера в её машинный код
  20. Язык ассемблера • Если у разработчика программного обеспечения будет персональный

    доступ к компьютеру: экран, клавиатура и возможность сохранять набранный внутри компьютера текст, • он сможет писать код на языке ассемблера и запускать его на ЭВМ самостоятельно, не привлекая оператора (взять на себя труд оператора) • Необходимое время для разработки программного обеспечения при этом заметно сократится • (возрастет производительность труда в области разработки ПО)
  21. Язык ассемблера • Программа, превращающая программы на языке ассемблера в

    машинный код, — транслятор • Программа, превращающая машинный код в программу на языке ассемблера, — дизассемблер
  22. Кстати • Некоторые пытливые умы посещает вопрос рано или поздно:

    как появился первый транслятор ассемблера в машинный код? • Набивание программы в машинном коде по современным меркам кажется невероятной «дичью» с запредельной трудоёмкостью • Кажется невероятным, чтобы кто-то действительно мог так разрабатывать реальную программу • Так, что «проблему» первого транслятора можно мысленно приблизить к проблеме «курицы и яйца»
  23. Кстати • Но это на первый взгляд, если не быть

    знакомым с эволюцией вычислителей • По сравнению с коммутационными досками машинный код — это очень хороший вариант по удобству и производительности • Очевидно, для первого транслятора дырявили машинный код • На второй взгляд: другого варианта просто быть не может • (todo: но было бы хорошо проверить точно)
  24. Языки высокого уровня • После ручного пробития машинного кода на

    перфокартах язык ассемблера кажется замечательным вариантом • Но даже в ассемблере (в современных вариантах), мы видим, начинают появляться т. н. мета-команды • Мета-команды — это такие команды, которые в программе на языке ассемблера занимают одну строчку, а транслятор превращает их, например, в две строки в машинном коде • Это может быть связано с перемещением чисел туда-сюда в памяти (достаточно большое число может потребоваться предварительно разрезать на куски, программисту легко ошибиться, а транслятор за него это сделает без ошибок как надо)
  25. Языки высокого уровня • По мере накопления опыта становится понятно,

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

    лаконичный, чем ассемблер, но который можно перевести на ассемблер • Так, чтобы последовательность команд на ассемблере в реальности выполняла то, что назначено смыслом лаконичной конструкции на языке высокого уровня
  27. Языки высокого уровня • При этом детали ассемблерной реализации могут

    быть стерты из контекста лаконичного языка • (например, не важно какой регистр использовать для промежуточных вычислений — главное, чтобы он был свободен; или не важно, какая ячейка памяти будет выбрана для переменной) • Абстрагироваться от деталей — перейти на более высокий уровень абстракции
  28. Языки высокого уровня • «Высокий уровень» — по уровню абстракции

    всё, что выше ассемблера • Иногда языки «высокого уровня» могут делить на «высокий» и «низкий» уровень внутри них самих, • т. е. какой-то язык высокого уровня может оказаться языком низкого уровня по сравнению с другим языком • В целом, это профессиональный сленг, а не строгая классификация
  29. Компилятор • Компилятор (сборщик) — это программа, которая переводит программу,

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

    благодаря лаконичности и уменьшения вероятности ошибиться (сокращения времени на отладку) • Сокращается время на перенос программ между вычислителями с разной архитектурой, т. е. разным набором машинных кодов и разными языками ассемблера (кросс-платфоменность) • Некоторое время при переходе на новую аппаратную платформу было нормальной практикой писать с нуля весь набор необходимых вспомогательных программ и подпрограмм • С появлением платформо-независимых языков высокого уровня, для переезда на новую платформу стало достаточно портировать компилятор
  31. Языки высокого уровня • Fortran (1957, IBM) — один из

    первых языков высокого уровня ru.wikipedia.org/wiki/Фортран • Си (англ. C) (1972, Bell Labs, Деннис Ритчи) — один из старейших языков высокого уровня, не теряющий актуальность («хоронителей» обычно «хоронили» раньше), фундамент ИТ-инфраструктуры ru.wikipedia.org/wiki/Си_(язык_программирования) • GCC (GNU C Compiler в составе GNU Compiler Collection, 1987, Ричард Столлман) — компилятор языка Си с исходным кодом, опубликованным под лицензией GPL. На текущий момент поддерживает множество аппаратных архитектур, один из популярнейших компиляторов и важнейших проектов для современной инфраструктуры ИТ gcc.gnu.org/wiki/History ru.wikipedia.org/wiki/GNU_Compiler_Collection
  32. Qt Creator: посмотреть ассемблерный код • Скомпилировать проект • Поставить

    точку останова (на последней строке) • Запустить в режиме отладки • Перейти в меню: Отладка > Уровень инструкций • (если не запустить в режиме отладки, это меню не будет доступно) • (в нашем случае ассемблерный код сгенерирован для архитектуры x86_64)
  33. • movl — загрузить константу в память (одна команда) •

    mov — загрузить значение из памяти в регистр или из регистра в память • %rbp — какой-то регистр (скорее всего указатель стека) • (%rbp - 0xс) — адрес в памяти переменной a • (%rbp - 0x8) — адрес в памяти переменной b
  34. Для архтитектуры MIPS • Набор инструментов для кросс-компиляции • (когда

    на одной архитектуре компилируете код для другой архитектуры) • (например: на компьютере x86_64 компилируете код для MIPS)
  35. Ubuntu + gcc + MIPS • В репозиториях два пакета

    (ставьте любой): - gcc-mips-linux-gnu - gcc-mipsel-linux-gnu ] apt-get install gcc-mipsel-linux-gnu После установки запускать: • gcc: mipsel-linux-gnu-gcc • objdump: mipsel-linux-gnu-objdump
  36. gcc + MIPS ] mipsel-linux-gnu-gcc prog-add.c -g -o prog-add-mipsel •

    prog-add.c — имя файла с исходным кодом программы • «-o prog-add-mipsel» — указать имя исполняемого файла (появится в текущем каталоге после компиляции) • «-g» — включить в исполняемый файл отладочную информацию (если опцию не указать, то файл будет скомпилирован, будет работать и его можно будет дизассемблировать, но на следующем шаге вместе с ассемблерным кодом не будет видно исходный код Си)
  37. prog-add-mipsel: формат файла elf32-tradlittlemips [...] Дизассемблирование раздела .text: [...] 004007b0

    <main>: #include <stdio.h> int main(void) { [...] int a = 9; 4007cc: 24020009 li v0,9 4007d0: afc2001c sw v0,28(s8) int b = 3; 4007d4: 24020003 li v0,3 4007d8: afc20020 sw v0,32(s8) int c = a + b; 4007dc: 8fc3001c lw v1,28(s8) 4007e0: 8fc20020 lw v0,32(s8) 4007e4: 00621021 adduv0,v1,v0 4007e8: afc20024 sw v0,36(s8) printf("%d + %d = %d\n", a, b, c); [...] ] mipsel-linux-gnu-objdump -S prog-add-mipsel
  38. gcc + x86_64 • Всё полностью аналогично • Просто запускать

    gcc и objdump как «gcc» и «objdump» • gcc создаст исполняемый файл для архитектуры x86_64 • objdump дизассемблирует в инструкции x86_64
  39. • Определение — это такое качество предмета, которое сохраняется в

    изменениях предмета • Попробуем определить программу
  40. Программа — это идея, • отвечающая на вопрос, что будет

    делать вычислительный механизм, • сформулированная на специальном языке, • который путем формально-логических преобразований может быть переведен в машинный код вычислителя.
  41. Машинный код, • будучи перенесен (записан) на специальный носитель, может

    быть подключен к вычислителю в качестве составной детали, • после чего вычислитель произведет действия, заложенные в программе, • Т.е. воплотит идею программы в жизнь
  42. Язык ассемблера и машинный код • Машинный код сам по

    себе тоже является программой • Но обычно используется более удобное представление — язык ассемблера • Удобное для чтения человеком • Можно сказать, что это человекочитаемое представление машинного кода (с оговорками) • Программа на языке высокого уровня обычно сначала переводится на язык ассемблера • После этого из языка ассемблера уже генерируется машинный код
  43. Язык ассемблера и машинный код • По форме программа состоит

    из последовательности инструкций (команд) • Инструкция состоит из логики (код команды) и данных (параметры команды) • Данные могут быть объединены с логикой в рамках одной инструкции или разнесены по разным ячейкам памяти (обычно работает смешанный вариант)
  44. Самостоятельно • Установите Qt Creator • Установите набор инструментов gcc

    • Запустите тестовый код — простую математическую формулу • Например: значение полинома 2*x^2 + x + 41 при разных x = 7, 14, 129 • Посмотрите ассемблерный код дизассемблированный из исполняемого файла • (можно просто x86_64, но лучше и с вариантом MIPS)
  45. Самостоятельно • Подумайте в контексте истории о модном технологическом тренде

    — программы (ИИ), которые пишут другие программы • Где их место цепочке технологий или они из неё выбиваются как нечто совсем новое, чего еще раньше не было • Какова будет их роль и влияние (если предположить, что хотя бы один проект будет реализован до рабочего состояния) • Получится ли благодаря им исключить человека из процесса разработки программного обеспечения, как об этом мечтают адепты