Skip to content
/ hw_01 Public
forked from uniyar-os/hw_01

Домашняя работа № 1

Notifications You must be signed in to change notification settings

Denis442/hw_01

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

Домашняя работа № 1: Исполняемые файлы

1. Настройка

1.1. GitHub

Результаты домашних работ должны быть представлены на GitHub, для чего у тебя должна быть там учётка. Свой код надо хранить строго в приватных репозиториях.

1.2. Vagrant

Для выполнения заданий потребуется использовать готовый преконфигурированный Vagrant-образ виртуальной машины, который содержит все необходимые инструменты для запуска, тестирования и отладки кода. Vagrant — это средство управления виртуальными машинами, он будет использоваться для загрузки и запуска подготовленного образа виртуальной машины.

ℹ️
Только для пользователей Windows

Поскольку Windows не поддерживает ssh, команда vagrant ssh, которая потребуется в дальнейшем, приведет к ошибке. Vagrant предложит скачать Cygwin или что-то похожее, что поддерживает ssh. Cygwin — это набор программ (Linux команд) для Windows. Тебе необходимо поставить Cygwin и использовать его терминал для выполнения команд.

  1. Скачать с сайта Cygwin дистрибутив, подходящий к установленной версии Windows.

  2. Запустить скаченный файл (setupx84_64.exe или типа того).

  3. На экране приветствия нажать «Далее».

  4. На экране «Choose A Download Source» выбрать «Install from Internet» и нажать «Далее».

  5. На экране «Select Root Install Directory» нужно оставить предложенное значение для «Root Directory» и выбрать установку для всех пользователей «All Users». Нажать «Далее».

  6. На экране «Select Local Package Directory» ничего не трогать. Нажать «Далее».

  7. На экране «Select Your Internet Connection» выбрать «Direct Connection». Нажать «Далее».

  8. (Действие не требуется) Cygwin загрузит список доступных зеркал (то есть серверов на которых хранится программное обеспечение Cygwin).

  9. На экране «Choose A Download Site» нужно выбрать какой-нибудь сайт и нажать «Далее».

  10. (Действие не требуется) Cygwin загрузит список доступного программного обеспечения.

  11. Теперь ты попал на экран «Select Packages». Выбери из выпадающего списка «View» в верхнем левом углу «Full» вместо «Category». Больше ничего не трогать.

  12. Для каждого перечисленных ниже пакетов нажми на надпись «Skip», чтоб выбрать этот пакет для установки. Поиск пакета удобно осуществлять с помощью строки поиска «Search». При нажатии на «Skip» надпись должна превращаться в номер версии пакета, типа 2.1.4-1. Возможно некоторые пакеты уже будут выбраны для установки, тогда нажимать ничего не надо.

    Пакет

    Описание

    bash

    THE GNU Bourne Again SHell

    git

    Distributed version control system

    openssh

    The OpenSSH server and client programs

  13. Нажми «Далее» для проверки списка установки.

  14. На экране «Resolving Dependencies» удостоверься, что выбран пункт «Select required packages» и нажми «Далее».

  15. (Действие не требуется) Cygwin установит все выбранные пакеты.

  16. На экране «Create Icons» лучше выбрать оба пункта «Desktop icons» и «Start Menu icons», чтобы было легче отыскать «Cygwin Terminal». Нажми «Finish» для завершения.

Все последующие команды следует вводить в терминале «Cygwin Terminal».

  1. Vagrant зависит от VirtualBox (программное обеспечение с открытым программным кодом для виртуализации), поэтому прежде всего необходимо загрузить и установить свежую версию с сайта VirtualBox.

  2. Установить свежую версию с сайта Vagrant.

  3. После установки Vagrant нужно ввести в терминал следующие команды:

    $ mkdir cs162-vm
    $ cd cs162-vm
    $ vagrant init cs162/spring2019
    $ vagrant up
    $ vagrant ssh

    Эти команды приведут к тому, что произойдет загрузка подготовленного образа виртуальной машины, она будет запущена и будет поднято ssh-соединение с хоста в виртуальную машину. Отметим, что команда «up» требует для выполнения достаточно много времени и устойчивое соединение с интернетом.

  4. Все vagrant-команды требуется запускать из директория cs162-vm, который был создан ранее. Нельзя удалять этот директорий, иначе vagrant не будет знать как управлять виртуальной машиной (ВМ), которая была создана.

  5. Команда vagrant halt приведёт к остановке виртуальной машины. Для следующего запуска ВМ достаточно ввести только две команды:

    vagrant up
    vagrant ssh

1.2.1. Решение проблем с Vagrant

Если команда vagrant up выпадает с ошибкой, попробуй выполнить vagrant provision и проверить не исправит ли она ошибку. Если совсем всё плохо, можно попробовать полностью удалить ВМ командой vagrant destroy. Потом снова создать ВМ vagrant up.

1.2.2. Имя пользователя Git и емейл

Выполни эти команды чтобы настроить имя пользователя и емейл, которые будут использоваться в git-коммитах. Не забудь заменить ТВОЁ_ИМЯ и ТВОЯ_ПОЧТА_КОМ на нормальное имя (лучше латиницей) и на нормальную почту.

$ git config --global user.name "ТВОЁ_ИМЯ"
$ git config --global user.email "ТВОЯ_ПОЧТА_КОМ"

1.2.3. ssh-ключи

Для того, чтобы можно было изнутри ВМ работать с GitHub нужно настроить ssh-ключи.

В терминале ВМ нужно выполнить:

$ ssh-keygen -N "" -f ~/.ssh/id_rsa
$ cat ~/.ssh/id_rsa.pub

Первая команда создает новую пару ssh-ключей. Вторая команда выводит на экран публичный ключ. Для доступа к GitHub по ключам нужно перейти по ссылке https://github.com/settings/keys и добавить показанный на экране публичный ключ к GitHub-аккаунту. Можно назвать этот ключ произвольным образом, но лучше, чтобы название что-то обозначало, например, «OS_VM». Ключ должен начинаться с «ssh-rsa» и заканчиваться «vagrant@development».

1.2.4. Репозитории

При выдаче любого задания, включая это, будет предоставлена ссылка, ведущая на GitHub Classroom (надстройка над GitHub для ведения занятий). После перехода по этой ссылке системой будет предложено принять задание, нажав кнопку «Accept this assignment». При этом на GitHub будет создан индивидуальный репозиторий с начальными файлами задания, которые надо будет дополнить. Например, для этого задания будет создан индивидуальный репозиторий с адресом https://github.com/uniyar-os/hw-01-твой_github_юзернейм. Этот репозиторий будет приватным — данные находящиеся в нём будут доступны только студенту и преподавателю.

Теперь следует: Для этого в терминале ВМ:

  1. Сделать копию репозитория (клон) в ВМ.

    $ git clone [email protected]:uniyar-os/hw-01-твой_github_юзернейм.git
  2. Удостовериться, что в текущем директории внутри ВМ появилась папка hw-01-твой_github_юзернейм.

    $ ls

    Именно в в папку hw-01-твой_github_юзернейм «склонирован» удаленный репозиторий, и именно в ней следует работать с файлами, регулярно фиксируя изменения в файлах (git commit) и отправляя (git push) эти изменения в удаленный репозиторий.

  3. Перейди в папку hw-01-твой_github_юзернейм командой:

    $ cd w-01-твой_github_юзернейм

1.3. Редактирование файлов в ВМ

В образ ВМ добавлена поддержка удаленного доступа к файлам (SMB-сервер), которая позволяет редактировать файлы внутри папки ВМ пользователя vagrant (именно в нее ты склонировал репозиторий). То есть можно доступиться до папки ВМ с помощью текстовых редакторов установленных на хостовой системе. Это рекомендуемый способ работы с файлами в этом курсе. Есть и другие, менее удобные способы. Например использовать текстовые редакторы (nano, vim) непосредственно в терминале.

1.3.1. Windows

  1. Открой проводник, нажми Ctrl+L для фокусировки на элементе ввода расположения.

  2. Напечатай \\192.168.162.162\vagrant и нажми Enter.

  3. Имя пользователя vagrant, пароль vagrant.

Тебе должно быть видно содержимое директория пользователя vagrant, в том числе и hw-01-твой_github_юзернейм.

1.3.2. Mac OS X

  1. Открой Finder.

  2. В меню выбери «Переход → Подключение к серверу…​»

  3. В строке адреса вбей smb://192.168.162.162/vagrant.

  4. Имя пользователя vagrant, пароль vagrant.

Тебе должно быть видно содержимое директория пользователя vagrant, в том числе и hw-01-твой_github_юзернейм.

1.3.3. Linux

Используй любой smb-клиент для присоединения к папке /vagrant, расшареной на 192.168.162.162 c именем пользователя vagrant и паролем vagrant. Вероятно обозреватель файлов твоего дистрибутива поддерживает smb «из коробки» — обратись за инструкциями к документации.

2. Инструменты для работы

Перед продвижением следует пробежаться по полезным инструментам, которые входят в набор любого хакера. Умение пользоваться некоторыми из них (например git, make) совершенно необходимо при выполнении заданий этого курса. Другие, например gdb или tmux, являются усилителями продуктивности. Первая из них помогает искать ошибки в коде, вторая позволяет использовать многозадачность более эффективно. Все описанные ниже инструменты уже находятся внутри ВМ и готовы к использованию.

ℹ️
Этот документ не является исчерпывающим руководством по рассматриваемым инструментам. Вместо этого ниже будут предоставлены ссылки на внешние ресурсы описывающие способ работы с тем или иным инструментом. Крайне рекомендуется ознакамливаться со всеми предлагаемыми материалами, даже если они не требуется для выполнения задания.

2.1. Git

Git — это средство контроля версий, которое помогает отлеживать изменения в коде. GitHub — это один из множества сервисов для размещения кода. Можно пользоваться git локально, но проталкивать (git push) изменения в GitHub для удобной совместной (с преподавателем) работы.

Возможно, что ты уже знаком с некоторыми командами git, однако понимание внутренних механизмов работы скрывающихся за относительно простыми командами позволит более глубоко понимать и предсказывать поведение этого инструмента.

Если ты никогда раньше не использовал git и хочешь разобраться «с самого начала», то начни отсюда.

2.2. make

Программа make предназначена для автоматического создания исполняемых файлов и библиотек из исходного программного кода. Построение исполняемых файлов описывается с помощью правил, определенных в файле Makefile, который обычно располагается в корневом директории проекта, который требуется построить. Правила работают довольно интересно: в файле Makefile с помощью особого синтаксиса описывается список зависимостей и make анализируя этот файл строит граф зависимостей для построения всего, что требуется. К сожалению особый синтаксис довольно особый, временами он может сбивает с толку, особенно если ты плохо понимаешь, что в действительности делает make.

Документацию на русском можно найти здесь, а практическое руководство с примерами тут. Конечно же лучше всего читать официальную документацию на английском тут.

Попробуй применить простейший способ использования make (без Makefile). Находясь в директории с заданием, можно скомпилировать и слинковать wc.c просто выполнив:

$ make wc

В результате будет создан исполнимый файл wc, который можно запустить. Попробуй:

$ ./wc wc.c

А если так? (Подсказка: чтоб разобраться что происходит выполни which wc.)

$ wc wc.c

Твоё первое задание будет состоять в том, чтобы модифицировать заготовку wc.c, так, чтобы твоя программа работала также как утилита wc, встроенная в Linux. Спецификацию утилиты wc можно прочитать так: man wc. Важно! Тебе не надо реализовывать поддержку флагов и опций — достаточно просто обрабатывать файл (если файл не задан, то брать входные данные из SDTIN).

2.3. gdb

Отлаживать программы на C тяжело. Катастрофические ошибки (крэши) по-умолчанию не выводят ни человекочитаемых объяснений наступивших проблем, ни состояния стека (порядок вызовов). К счастью есть gdb. Если при компиляции использовать флаг -g, то в результирующем исполнимом файле будет содержаться необходимая для отладки дополнительная информация (debug symbols), именно она позволяет gdb делать магию. При запуске программы из-под gdb ты сможешь не только следить за состоянием стека, но также проверять значения переменных, менять их, приостанавливать исполнение и много еще чего!

Обычный вариант gdb поддерживает очень простой интерфейс, поэтому в образе ВМ, который ты используешь, предустановлена более развесистый вариант этого дебаггера — cgdb (подсветка синтаксиса и несколько дополнительных удобных фичей). Переключение между верхней и нижней панелью в cgdb осуществляется с помощью i и ESC.

Утилита gdb может запускать новые процессы и прикреплять их (attach) к существующим процессам (это может быть полезным для отладки твоего кода).

Что почитать: переводная статья на Хабре, туториал на английском и, как всегда, хорошая, но многословная официальная документация.

Разберись как отлаживать программы на примере wc:

  • При компиляции файла wc.c с помощью компилятора gcc добавь флаг -g.

  • Запусти получившийся исполнимый файл из-под gdb.

  • Установи точку останова (break point, брекпойнт) на функции main.

  • Исполни программу до брекпойнта.

  • Попробуй разные команды gdb.

  • Разберись как передавать аргументы командной строки.

  • Добавь в main локальные переменные и попробуй проверить из значения.

  • Изучи команды step, next и break.

2.4. tmux

Программа tmux — мультиплексор терминала, позволяющий в одной терминальной сессии симулировать несколько консолей.

Запуск новой tmux-сессии осуществляется так:

$ tmux new -s <имя_сессии>

После создания новой сессии ты увидишь обычный терминал. Нажатие ctrl-b + c приведет к созданию новой консоли, переключить фокус ввода между которыми можно комбинацией ctrl-b + n, где n — номер консоли. Комбинации клавиш ctrl-b + % и ctrl-b + " позволяют разделить консоль на две, вертикально и горизонтально соответственно.

Для открепления (detach) от tmux примени ctrl-b + d. Сессия tmux со всеми созданными консолями и запущенными в них программах продолжает существовать и работать. Вернуться в неё можно так:

tmux attach -t <имя_сессии>

Самая впечатляющая особенность в том, что можно отключить ssh-соединение, а tmux-сессия, созданная в нём продолжит работать. Более того после переподключения по ssh к tmux-сессии можно опять приаттачиться, как это показано выше.

2.5. vim

Программа vim — удобный текстовый редактор для терминала. Стоит научиться использовать его (Учебник на русском, ещё один учебник), хотя некоторые предпочитают emacs.

Какой бы редактор ты не выбрал, нужно научиться правильно и эффективно использовать его для написания кода.

Если тебе удобнее и/или привычнее использовать оконный редактор текста (Sublime, VSCode или что-то другое) обратись к разделу, где написано про доступ в файлам ВМ с хоста.

2.6. ctags

Инструмент ctags облегчает навигацию по проектам с большим количеством кода, он может сэкономить много времени. Помимо всего прочего ctags позволяет перескакивать к любому заданному имени (символу) в коде. Если совместить эту возможность с возможностью текстового редактора запоминать переходы «вперед-назад», это очень облегчит анализ кодовой базы.

  • Инструкции по установке ctags в vim здесь.

  • Инструкции по установке ctags в Sublime здесь.

Если для редактирования кода тобой используется какой-то другой текстовый редактор, то с большой долей вероятности он тоже поддерживает ctags, надо просто самостоятельно отыскать инструкцию.

3. Задания

3.1. make

Есть шанс, что ты когда-то использовал gcc для компиляции программ, однако непосредственное применение такого подхода при увеличении количества файлов с исходным кодом приводит к необоснованной сложности запуска процесса компиляции. В этом задании тебе требуется написать Makefile, который будет управлять компиляцией main.c, wc.c и map.c (возможно есть смысл в том, чтобы добавить флаг -g к gcc на этом шаге). Также неплохой мыслью было бы написать правило для удаления бинарных файлов, вызываемое командой make clean. Если не всё сказанное понятно, прочитай ещё раз раздел 2.2.

Не забудь зафиксировать изменения с помощью git и протолкнуть их на GitHub.

3.2. wc

Начать думать на C поможет задачка с файлов wc.c. При работе над ней особое внимание удели тому, как приложения используют операционную систему: передача аргументов из командной строки, чтение файлов, стандартные дескрипторы файлов.

Твоя задача в том, чтобы создать ограниченный клон известной утилиты wc, которая, в заданном текстовом файле, подсчитывает количество строк, слов и символов. Попробуй позапускать оригинальную wc в ВМ, чтобы понять как она работает и сделать так же в wc.c (функциональность дополнительных аргументов реализовывать не надо). Достаточно реализовать поддержку двух режимов запуска wc ИМЯ_ФАЙЛА и wc без аргументов. В последнем случае программа должна читать данные из стандартного потока STDIN.

При работе над этим заданием попрактикуйся с отладкой в gdb. Используй отладку для пошагового исполнения программы и проверки значений переменных.

Регулярно фиксируй состояния файла wc.c помощью git и проталкивай их на GitHub (бинарные исполняемые файлы добавлять в git неверно и преступно, разузнай поподробнее про .gitignore).

3.3. Исполняемые файлы и адреса

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

3.3.1. gdb

Запусти твой вариант wc из-под gdb указав файл для анализа с помощью аргумента командной строки, создай точку останова (break point) при входе в функцию main, запусти выполнение до точки останова, пошагово дойди до середины программы. Посмотри на состояние стека используя команды where и/или backtrace (bt).

Создай файл gdb.txt и в любимом текстовом редакторе запиши в этот файл ответы на такие вопросы:

  1. Каково значение переменной argv? (подсказка: print argv)

  2. На что указывает argv? (подсказка: print argv[0])

  3. Каков адрес функции main?

  4. Попробуй выполнить info stack. Объясни, что видишь.

  5. Попробуй выполнить info frame. Объясни, что видишь.

  6. Попробуй выполнить info registers. В каких регистрах находится информация, которую ты можешь идентифицировать, как имеющую отношение к исполняемому коду?

Не забудь коммитнуть и протолкнуть результат.

3.3.2. objdump

В исполняемом файле скрывается больше, чем заметно на первый взгляд. Заглянем же внутрь. Запусти objdump -x -d wc и ты увидишь, что там есть: несколько сегментов, имена функций и переменных, связанных с адресами функций и величин. Заметь, что все кишочки программы разбиты на куски, хранящиеся в сегментах.

В выводе objdump эти сегменты перечислены после заголовка Sections. Ты можешь подразобраться с терминологией, поискав информацию в интернете.

Создай файл objdump.txt и, разглядывая вывод objdump, ответь в нём на следующие вопросы:

  1. Какой формат используется в этом бинарном файле? Какая архитектура поддерживается?

  2. Какие имена сегментов/секций тебе известны?

  3. Какой сегмент/секция содержат функцию main и какой у неё адрес? (Отличается ли от от того, что был известен из gdb?)

  4. Видишь ли ты сегмент стека (stack)? А сегмент кучи (heap)? Объясни.

Добавь файл с ответами в git.

3.3.3. map

Так! Теперь ты готов приступить к программе, которая покажет свою же структуру в памяти. Второй файл из задания map.c — заготовка, которая готова чуть менее, чем полностью. Нужно её модифицировать для получения адресов, которые понадобятся для решения. Результат выполнения программы должен быть примерно такой (адреса могут отличаться).

_main  @ 0x4005c2
recur @ 0x40057d
_main stack: 0x7fffda11f73c
static data: 0x601048
Heap: malloc 1: 0x671010
Heap: malloc 2: 0x671080
recur call 3: stack@ 0x7fffda11f6fc
recur call 2: stack@ 0x7fffda11f6cc
recur call 1: stack@ 0x7fffda11f69c
recur call 0: stack@ 0x7fffda11f66c

Обдумай следующие вопросы и запиши ответы в файл map.txt.

  1. Используй objdump с флагом -D на исполняемом файле map. Какие адреса из вывода ./map определены в исполнимом файле? В каком сегменте/секции каждый из них расположен?

  2. Составь список важных сегментов и поясни какова роль каждого из них. (Поищи, если нужно, в интернете их названия.)

  3. В каком направлении растет стек?

  4. Каков размер стек-фрейма для каждого рекурсивного вызова?

  5. Где куча? В каком направлении она растет?

  6. Являются ли две области памяти выделенные с помощью malloc() смежными? Есть ли между ними некоторое незанятое пространство?

Не забывай про git.

3.4 Пользовательские ограничения

Операционная система имеет дело с размерами динамически меняющихся сегментов: стек и куча. Сколько памяти надо резервировать для них? Отыщи способ для изменения этих ограничений в Linux (тебе понадобится интернет).

Измени файл main.c так, чтобы при выполнении он выводил максимально доступный размер стека, максимально возможное количество процессов и максимальное количество дескрипторов файлов. В начале при компиляции и запуске main.c будет выведена информация об ограничениях. К сожалению все значения будут равны нулю. Твоя задача сделать так, чтобы программа вывела действительные ограничения, налагаемые операционной системой (используй мягкие ограничения, а не жёсткие). (Подсказка: запусти man getrlimit).

Результат должен быть примерно таким:

stack size: 8388608
process limit: 2782
max file descriptors: 1024

Результат, как и всегда, следует зафиксировать в git и отправить в GitHub.

Всё!

About

Домашняя работа № 1

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 100.0%