В этом случае, почему мы знаем, что значение% rbp и, следовательно,% rbp-4 выровнено 4, чтобы подходить для хранения / загрузки int?
В этом конкретном случае мы знаем, что мы находимся на процессоре x86, на котором любой адрес подходит для загрузки и хранения целого числа. Вызывающая сторона может уменьшать или смещать ранее выровненный %rbp
на 17, и это не будет иметь никакого значения, кроме, возможно, производительности.
Тем не менее, это выравнивается Почему мы знаем, что это инвариант системы, которой мы доверяем, что требуется ABI. Если указатель стека не выровнен, это означает, что вызывающая сторона нарушила аспект соглашений о вызовах.
Если мы не принимаем вызов из отдельного домена безопасности (например, ядро получает системный вызов из пространства пользователя), мы просто доверяем вызывающей стороне. Как функция strcmp
знает, что ее аргументы указывают на допустимые строки с нулевым символом в конце? Это доверяет звонящему. То же самое.
Если функция получает выровненный %rsp
и гарантирует, что все манипуляции с ней сохраняют выравнивание, то любые вызовы функций , которые она вызывает, также получают выровненный %rsp
. Обеспечение того, что все вызовы выполняются с требуемым выравниванием стека, обеспечивается компилятором. Если вы пишете ассемблерный код, вы должны убедиться в этом сами.
Как компилятор может выровнять членов структуры, если ничего не известно о выравнивании начального адреса структуры во время компиляции?
Члены struct
получают смещения в предположении, что базовый адрес времени выполнения объекта будет соответствующим образом выровнен даже для самого строго выровненного члена структуры. Вот почему первый член структуры просто помещается с нулевым смещением, независимо от его типа.
Время выполнения должно гарантировать, что любой адрес, выделенный для произвольного объекта, имеет строжайшее выравнивание любого стандартного типа, alignof(maxalign_t)
. Например, если самое строгое выравнивание в системе составляет 16 байтов (как в x86-64 System V), тогда malloc
должен выдавать указатели на 16-байтовые выровненные адреса. Тогда любой тип структуры может быть помещен в полученную память.
Если вы напишите свой собственный предположительно универсальный распределитель, который раздает 4-байтовые совмещенные указатели в системе, где выравнивание может быть столь же строгим, как 16, то это неправильно.
(Обратите внимание, что типы __m256
и __m512
не учитываются для maxalign_t
: malloc
по-прежнему обеспечивает только 16-байтовое выравнивание в x86-64 System V и недостаточно для избыточного выровненные типы, такие как __m256
или пользовательские struct foo { alignas(32) int32_t a[8]; };
. Используйте aligned_alloc()
для выровненных типов.)
Также обратите внимание, что формулировка в стандарте ISO C гласит, что память, возвращаемая malloc
, должна использоваться для любого типа. 4-байтовое распределение в любом случае не может содержать 16-байтовый тип, поэтому небольшие распределения могут быть выровнены менее чем на 16 байтов.