Включая библиотеку в C, где она размещается в адресном пространстве? - PullRequest
0 голосов
/ 23 мая 2018

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

Я знаю, что: глобальные переменные находятся в разделе данных.статические переменные находятся в разделе данных.локальные переменные находятся в секции стека.Динамическое выделенное пространство находится в разделе кучи.Мои вопросы: когда библиотека включается в программу, где она находится в адресном пространстве?

Надеюсь, этот вопрос имеет смысл ..

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Вы исходите из плохой предпосылки:

Я понимаю, как адресное пространство разделено на: код, данные, стек и кучу.Однако у меня возникают проблемы с отображением того, куда и куда направляется данный код C.

Адресное пространство не разбивается таким образом.Адресное пространство содержит память.Память, используемая для стека, неотличима от памяти, используемой для кучи.Единственное, что делает стек стеком, - это то, что он выделяется в приложении с помощью указателя стека.Единственная вещь, которая делает кучу кучей, это то, что в приложении есть менеджер кучи.Вы могли бы выделить память из кучи и назначить ее указателю аппаратного стека, а ваша память - это и куча, и стек.

Вот еще одно неправильное представление:

Я знаю, что: глобальныйпеременные находятся в разделе данных.статические переменные находятся в разделе данных.локальные переменные находятся в секции стека.Динамическое выделенное пространство находится в разделе кучи.

Чем отличаются работники между ассемблерами, компоновщиками и системами.Однако рациональные ассемблеры позволяют пользователю определять свои собственные именованные разделы.Во многих ассемблерах я мог создавать Bobs_Data_Section, Freds_Data_Section и Sams_Data_section и помещать глобальные переменные в каждый из них.

В большинстве (но не во всех) компиляторах программист не может контролировать, как он собирается создавать разделы,Нет никакой гарантии, что компилятор поместит глобальные переменные в раздел под названием «данные».Фактически, глобальные переменные и статические локальные переменные могут находиться в одном и том же разделе.

Такие «разделы» обычно являются только входными данными для компоновщика.Компоновщик группирует разделы, определенные ассемблером и компилятором, в области памяти с общими атрибутами доступа.То, что входит в компоновщик, как, скажем, секция «данных», выходит из компоновщика в виде инструкций в исполняемом файле для создания страниц для чтения / записи.

У меня есть вопросы при включении библиотекив программу, где она находится в адресном пространстве?

Итак, теперь вы столкнулись с проблемой того, как вы пытаетесь узнать, как все работает.Если вы рассматриваете адресное пространство процесса как просто память, вы можете загрузить библиотеку куда угодно.Загрузчик программы читает инструкции в исполняемом файле и создает страницы с правильными атрибутами (например, readonly / noexecute, read / write, readonly / execute) в любом месте доступного адресного пространства.

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

0 голосов
/ 23 мая 2018

На самом деле, если у вас есть ПК на базе Linux, вы можете проверить его самостоятельно следующим образом:

  1. создать простое приложение c с бесконечным циклом while внутри main ().
  2. compile

    $ gcc -o main ./main.c -g

  3. launch

    $ gdb ./main

  4. Показать информацию о сопоставлении

    (gdb) r

    (gdb) Информация о преобразованиях процессов

    Отображенные адресные пространства:

          Start Addr           End Addr       Size     Offset objfile
            0x400000           0x401000     0x1000        0x0 /tmp/main
            0x600000           0x601000     0x1000        0x0 /tmp/main
            0x601000           0x602000     0x1000     0x1000 /tmp/main
            0x602000           0x623000    0x21000        0x0 [heap]
      0x7ffff7a0d000     0x7ffff7bcd000   0x1c0000        0x0 /lib/x86_64-linux-gnu/libc-2.23.so
      0x7ffff7bcd000     0x7ffff7dcd000   0x200000   0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
      0x7ffff7dcd000     0x7ffff7dd1000     0x4000   0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
      0x7ffff7dd1000     0x7ffff7dd3000     0x2000   0x1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
      0x7ffff7dd3000     0x7ffff7dd7000     0x4000        0x0
      0x7ffff7dd7000     0x7ffff7dfd000    0x26000        0x0 /lib/x86_64-linux-gnu/ld-2.23.so
      0x7ffff7fd4000     0x7ffff7fd7000     0x3000        0x0
      0x7ffff7ff6000     0x7ffff7ff8000     0x2000        0x0
      0x7ffff7ff8000     0x7ffff7ffa000     0x2000        0x0 [vvar]
      0x7ffff7ffa000     0x7ffff7ffc000     0x2000        0x0 [vdso]
      0x7ffff7ffc000     0x7ffff7ffd000     0x1000    0x25000 /lib/x86_64-linux-gnu/ld-2.23.so
      0x7ffff7ffd000     0x7ffff7ffe000     0x1000    0x26000 /lib/x86_64-linux-gnu/ld-2.23.so
      0x7ffff7ffe000     0x7ffff7fff000     0x1000        0x0
      0x7ffffffdd000     0x7ffffffff000    0x22000        0x0 [stack]
    

Итак, мы видим, что ld-so разместил c библиотеку по адресам 0x7ffff7bcd000 - 0x7ffff7dd5000.Поле смещения - это смещение в самом файле ELF.Мы можем проверить, какие разделы соответствуют какому смещению, используя readelf:

$ readelf -a /lib/x86_64-linux-gnu/libc-2.23.so | less

Пример:

 [13] .text             PROGBITS         000000000001f8b0  0001f8b0
       0000000000153214  0000000000000000  AX       0     0     16

Это означает, что сечение .text имеет смещение 0x1f8b0.Из приведенного выше сопоставления можно сделать вывод, что виртуальный адрес начала секции .text в адресном пространстве основного приложения будет 0x7ffff7bcd000 + 0x1f8b0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...