Как выглядит файл библиотеки (.dll) на диске с точки зрения .NET?

Ответ

Файл .NET сборки (DLL или EXE) — это PE-файл (Portable Executable), содержащий как стандартные Windows-заголовки, так и специфичные для .NET данные. Его структура выглядит так:

1. PE-заголовки (Portable Executable):

  • Стандартный заголовок DOS (для совместимости).
  • Заголовок PE, описывающий структуру файла для загрузчика Windows.
  • Таблицы секций (например, .text, .rsrc).

2. CLR-заголовок:

  • Указывает, что это управляемый .NET-модуль.
  • Содержит метаданные о требуемой версии CLR, точку входа (Main метод) и расположение других критических структур.

3. Метаданные .NET:

  • Это сердце сборки. Таблицы, полностью описывающие её содержимое:
    • Таблица TypeDef: все классы, структуры, интерфейсы.
    • Таблица MethodDef: все методы с сигнатурами.
    • Таблицы FieldDef, PropertyDef, EventDef.
    • Таблица AssemblyRef: ссылки на другие зависимые сборки.
  • Метаданные позволяют CLR безопасно загружать и исполнять код, а также обеспечивают рефлексию.

4. IL-код (Intermediate Language):

  • Скомпилированный, но не нативный код ваших методов.
  • Хранится в секции .text.
  • JIT-компилятор (Just-In-Time) преобразует этот IL в машинный код во время выполнения.

5. Ресурсы (опционально):

  • Внедрённые файлы (иконки, строки, изображения), хранятся в секции .rsrc или как managed-ресурсы в метаданных.

Практический пример: Сборка, скомпилированная для .NET 6.0, будет иметь путь вида: C:ProjectsMyAppbinReleasenet6.0MyLibrary.dll

Как исследовать: Используйте инструменты вроде ildasm.exe (из .NET SDK) или dotPeek от JetBrains, чтобы увидеть эту структуру и декомпилировать IL-код обратно в C#.

Ответ 18+ 🔞

Вот, смотри, как это на самом деле устроено, если не забивать голову заумными книжками. Представь себе обычный .exe или .dll файлик. Снаружи — да, просто файл. А внутри — целый ёбаный космос, если знать, куда смотреть.

1. Башка файла (PE-заголовки): Это как паспорт и инструкция по сборке для самой Винды. Там лежит:

  • Какой-то древний, доисторический DOS-заголовок, чтобы, если запустить в MS-DOS, программа вежливо сказала бы «иди нахуй, это не для тебя».
  • Нормальный PE-заголовок — вот тут уже Винда понимает, как этот файл в память грузить, где что искать. Там же табличка с секциями: где код лежит (.text), где ресурсы (.rsrc) и прочая хуйня.

2. Объявление «я — .NET!» (CLR-заголовок): А вот это уже наш, родной. Эта штука кричит системе: «Эй, сука, я не простой, я управляемый! Мне нужна твоя CLR (виртуальная машина .NET), и именно вот такой версии!». Там же прописано, с какого метода Main начинать исполнение. Без этого заголовка CLR на файл даже смотреть не станет.

3. Самое сокровенное — метаданные (.NET Metadata): Вот это, блядь, главное. Это не просто данные, это полная и исчерпывающая схема всей твоей сборки, упакованная в аккуратные таблицы. Представь себе базу данных внутри файла:

  • TypeDef — кто тут у нас есть? Все классы, структуры, интерфейсы, перечисления. Полный список.
  • MethodDef — а что эти классы умеют? Все методы, с их именами, параметрами, возвращаемыми типами.
  • FieldDef, PropertyDef, EventDef — поля, свойства, события. Всё учтено, всё на виду.
  • AssemblyRef — а на кого мы, сука, завязаны? Список всех внешних сборок, которые нам нужны (типа System.Text.Json). Без них — пиздец, не запустимся.

Именно эти метаданные делают возможными две офигенные вещи: рефлексию (когда программа сама про себя всё узнаёт в рантайме) и безопасную загрузку (CLR точно знает, что и откуда брать, никаких левых сюрпризов).

4. Наш код, но не совсем (IL-код): Твой красивый C#-код компилятор переварил и превратил в IL (Intermediate Language) — это такой универсальный ассемблер для виртуальной машины .NET. Он не для процессора, он для CLR. Лежит это добро обычно в секции .text. А потом, когда программа запускается, приходит JIT-компилятор (Just-In-Time) и говорит: «А, IL? Щас, браток, переведу на твой родной машинный язык!» — и на лету генерирует настоящий процессорный код. Поэтому .NET-приложения иногда чуть дольше стартуют.

5. Всякая всячина (Ресурсы): Сюда можешь запихнуть иконки, картинки, локализованные строки, да что угодно. Могут лежать в классической секции .rsrc (как у всех нормальных Windows-программ) или как managed-ресурсы прямо внутри метаданных (более .NET-овый способ).


Практический пример, где это валяется: Скомпилировал ты библиотеку для .NET 6. Вот она, красавица, лежит: C:ProjectsMyAppbinReleasenet6.0MyLibrary.dll С виду — просто dll. А внутри — вся эта ебля, которую я описал.

Как самому залезть и посмотреть? Не веришь на слово? Да пожалуйста!

  • ildasm.exe — старый добрый дессемблер из .NET SDK. Запустишь его, откроешь свою DLL, и он тебе все эти заголовки, метаданные и IL-код разложит по полочкам. Прямо таблички покажет.
  • dotPeek от JetBrains или dnSpy — это уже серьёзные штуки. Они не только структуру покажут, но и IL-код обратно в почти читаемый C# попробуют декомпилировать. Удивляешься потом: «Охуеть, а это я так написал?».

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