понедельник, 29 июня 2015 г.

Системные вещи. Ответы Часть 1.

Введение

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

Я запишу лишь некоторый минимум, который мы хотели бы услышать от кандидата по каждому вопросу.

Что такое архитектура процессора?

Архитектура процессора — количественная составляющая компонентов процессора компьютера (например, регистры процессора).
С точки зрения программиста — совместимость с определённым набором команд (например, процессоры, совместимые с командами Intel х86), структуры команд и способ исполнения.
С точки зрения аппаратной составляющей вычислительной системы — это некий набор свойств и качеств, присущий целому семейству процессоров (например, RISC и CISC).

Здесь кандидат может получить жирный плюс в карму, если сможет рассказать про Arm и какие-то ее особенности. Не могу сказать, что мы активно используем эту архитектуру, но все же это будет отмечено на собеседовании. Ведь если кандидат смог разобраться в этой архитектуре самостоятельно, скорее всего сможет разобраться и в других сложных вопросах. Рассказ про особенности CISC и RISC так же будет большим плюсом.

Чем x86 отличается от x64?

Большинство кандидатов при ответе на этот вопрос начинают рассказывать о том, что в x86 компьютере нельзя использовать больше 3.5 Гб оперативной памяти. В этом случае мы сразу упоминаем про PAE и просим освятить этот вопрос поподробнее. К сожалению, пока ни один кандидат не смог ничего нам рассказать. На самом деле компьютеры вполне успешно использовали больше 3.5 Гб оперативной памяти и без новой архитектуры, а различий куда больше:
  1. Размер регистров процессора. Очевидно, что в x64 размер регистров общего назначения, арифметических и логических операций над целыми числами и виртуальных адресов стал равен 64-битам.
  2. Количество регистров процессора. 
  3. Новый режим работы Long mode.
Есть так же несколько отличий для программиста:
  1. Размер виртуального адресного пространства увеличился с 3.5 Гб до 20Гб.
  2. В C\C++ появились новые типы и изменился размер некоторых старых типов.
  3. Использование fastcall в качестве calling convention (смотри MSDN).
Для тех, кто решит капнуть этот вопрос максимально глубоко следует обратиться к мануалам от Intel.

Что такое защищенный и реальный режимы работы?

Вопрос про режимы работы процессора напрямую связан с вопросом, что такое адресс в памяти и на мой взгляд является одним из самых важных вопросов, с которыми сталкивается программист в C\C++. Ошибки работы с памяти или интерпретации тех или иных адессов являются одними из самых частых на моей практике. К моему большому сожалению, многие современные программисты не понимают как работает память в современном компьютере.
В реальном режиме при вычислении линейного адреса, по которому процессор собирается читать содержимое памяти или писать в неё, сегментная часть адреса умножается на 16 и суммируется со смещением. Таким образом, адреса 0400h:0001h и 0000h:4001h ссылаются на один и тот же физический адрес, так как 400h×16+1 = 0×16+4001h.
Такой способ вычисления физического адреса позволяет адресовать 1 Мб + 64 Кб − 16 байт памяти (диапазон адресов 0000h…10FFEFh). 

Защищённый режим — режим работы x86-совместимых процессоров.
Суть защищённого режима в следующем: программист и разрабатываемые им программы используют логическое адресное пространство. Логический адрес преобразуется в физический адрес автоматически с помощью схемы управления памятью (MMU). При этом содержимое сегментного регистра не связано напрямую с физическим адресом, а является номером сегмента в соответствующей таблице. Благодаря защищённому режиму, в памяти может храниться только та часть программы, которая необходима в данный момент, а остальная часть может храниться во внешней памяти (например, на жёстком диске).

Физический адрес формируется следующим образом. В сегментных регистрах хранится селектор, содержащий индекс дескриптора в таблице дескрипторов (13 бит), 1 бит, определяющий к какой таблице дескрипторов будет производиться обращение и 2 бита запрашиваемого уровня привилегий. Далее происходит обращение к соответствующей таблице дескрипторов и соответствующему дескриптору, который содержит начальный 24-битный адрес сегмента, размер сегмента и права доступа, после чего вычисляется необходимый физический адрес путём сложения адреса сегмента со смещением из 16-разрядного регистра.
Вопрос про режимы работы процессора тесно связан со страничной организацией памяти и будет кратко рассмотрен в других постах. За дополнительной информацией можно обращаться в wiki или к различной литературе.

Сегменты, IDT, GDT, LDT, TSS(TR)?

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

Таблица векторов прерываний (IDT) используется в архитектуре x86 и служит для определения корректного ответа на прерывания и исключения.
Начиная с процессора 80286, адрес в физической памяти и размер таблицы прерываний определяется 48-битным регистром IDTR.
В IDT используются следующие типы прерываний: аппаратные прерывания, программные прерывания и прерывания, зарезервированные процессором, называемые исключениями (первые 32) на случай возникновения некоторых событий.
В реальном режиме элементом IDT является 32-битный FAR-адрес обработчика прерывания.
В защищённом режиме элементом IDT является шлюз прерывания длиной 8 байт, содержащий сегментный (логический) адрес обработчика прерывания, права доступа и др.

GDT (глобальная таблица дескрипторов) — служебная структура данных в архитектуре x86, определяющая глобальные сегменты. Её расположение в физической памяти и размер определяются системным регистром GDTR.
Дескрипторы LDT и сегментов задач (TSS) могут находиться только здесь.
Особенностью GDT является то, что у неё запрещён доступ к нулевому дескриптору. Обращение к нему вызывает исключение #GP, что предотвращает обращение к памяти с использованием незагруженного сегментного регистра.

LDT (локальная таблица дескрипторов). В отличие от GDT, LDT может быть много (соответственно количеству потоков, но не обязательно). Каждая задача может иметь свою. На расположение таблицы текущей задачи указывает регистр LDTR.
Размер и расположение LDT в линейной памяти определяются дескриптором LDT из GDT (но это не означает, что размер LDT может быть больше 65536 байт).

TSS (сегмент состояния задачи) — специальная структура в архитектуре x86, содержащая информацию о процессе. Может использоваться ОС для диспетчеризации задач, но обычно применяется только для переключения на стек ядра при обработке прерываний и исключений. В TSS содержится информация о:
  • Состоянии регистров процессора;
  • Разрешениях на использование портов ввода-вывода;
  • Указатели на стек внутреннего уровня;
  • Ссылка на предыдущую запись TSS (для задач диспетчеризации)
На этом на сегодня всё. Остальные ответы читайте в следующем посте.

Наши собеседования и наши вопросы

Введение

За последний год работы в компании мне довелось провести более 50 собеседований. Большинство из них проводилось на позицию программист-стажер\программист C\C++.

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

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

Мне такой слегка хаотичный порядок сразу не понравился. Порой собеседования проводят разные люди, при этом вопросы у каждого в голове свои и отличаются от вопросов коллег. Это может привести к тому, что одна из областей не будет затронута вообще и вы возьмете неподходящего кандидата. Дабы избежать таких проблем, мы составили 2 списка вопросов (для стажеров и опытных программистов), а затем и небольшой тест, который проходят кандидаты перед собеседованием. Данный тест позволяет оценить базовые знания кандидата и не тратить время на дальнейшее собеседование в случае, если такие знания отсутствуют. Также мы используем лист с тестом для записи комментариев и оценок по каждой области после собеседования. Он отлично помогает вспомнить каждого конкретного кандидата после многих собеседований.

Наш тест вряд ли будет кому-то интересен, поэтому и публиковать его я не буду. А вот наши вопросы и, соответственно, ответы на них приведу в конце данного поста. Возможно эти вопросы помогут кому-то в подготовке к собеседованию (почему-то в интернете не так много вопросов для подготовки к собеседованию на должность программиста С\С++).

Всем хочется проводить собеседование "активного", подготовленного кандидата. Я, например, очень надеюсь, что кто-то из наших кандидатов придет подготовленным. К сожалению, на данный момент мой опыт собеседований весьма негативный. Большинство кандидатов, которые приходят к нам в компанию, обладают крайне низким уровнем знаний.  Конечно, студент, приходящий на собеседование, редко когда обладает большим багажом знаний и навыков. Но когда технический специалист после 3-4 курса института не знает, что такое DNS, как применяется ключевое слово static, то это п....ечально. Еще печальнее, что такие знания порой отсутствуют у людей имеющих 1-2-3 года работы на схожих позициях :(.

Очень хотелось бы знать, почему такие ситуации имеют место быть. Пока, к сожалению, я не могу назвать причину происходящего. Возможно, дело в том, что компания предлагает среднюю зарплату в городе. Или в том, что все серьёзные программисты едут работать из Зеленограда в Москву.

P.S. Замечу, что помимо вопросов к собеседованию я планирую постепенно публиковать ответы, которые мы ожидаем от кандидатов. Как вы видите, список вопросов достаточно обширный и захватывает многие около-компьютерные вопросы. Стоит отметить, что мы не мучаем кандидата всеми этими вопросами. Но если мы понимаем, что в данной области человек обладает какими-то знаниями, то мы стараемся копнуть как можно глубже, чтобы выяснить границу его знаний.

Вопросы и ответы


Итак, первая часть вопросов - Системные вещи:
  1. Что такое архитектура процессора? Чем x86 отличается от x64?
  2. Что такое защищенный и реальный режимы работы? Сегменты, IDT, GDT, LDT, TSS(TR)?
  3. Что такое режим ядра и режим пользователя? CPL, RPL, DPL?
  4. Как происходит взаимодействие между режимом пользователя и ядра? SYSENTER, int2e?
  5. Что такое виртуальная память? Как работает paging? PAE, x64, IOMMU?
  6. Что такое прерывание? Какие они бывают? Как происходит их обработка? Что со стеками?
  7. Подробно как происходит загрузка компьютера? А с UEFI?
  8. Что такое ядро ОС? Какие функции оно выполняет? Почему DOS не является ОС?
  9. Что такое драйвер? Чем он отличается от обычной программы?
  10. Что такое поток? Что он включает? Как и кем создается? В каких состояниях может быть?
  11. Что такое HAL? Зачем он нужен?
  12. Форматы исполняемых файлов(ELF, COFF(PE)). Секции, таблица релокаций, PIC?
  13. Что такое реестр? Как он устроен? Где храниться?
  14. Что такое сервис (служба)? Чем он отличается от обычной программы?
  15. Что такое Unicode, какое отношение к нему имеют UTF16, UCS2LE, UTF8 и т.д.?