Цитата(kentarchos @ Dec 25 2013, 15:34)

Спасибо всем! Впервые слышу такое название для чисел формата/стандарта 754. Но у меня возникает тогда вопрос: зачем выравнивать стек, если в стеке хранятся 32-битные регистры, а в куче могут храниться данные разных типов? И потом этоже выравнивание всего сегмента целиком.
Или я все неправильно понимаю?
Если посмотрите описание языка ассемблера KEIL, то обнаружите там две директивы -- кажется, PRESERVE8 и REQUIRE8, точно не помню. Они соответственно указывают, что данный модуль на языке ассемблера гарантирует сохранность 8-байтового выравнивания стека или требует, чтобы стек был выровнен на 8-байтовую границу (без них считается, что стек выровнен только на 4-байтовую границу). Компиляторы языков высокого уровня вроде бы порождают код, гарантирующий такое выравнивание (специально я этим вопросом не интересовался; при желании можно порыться в документации). Компоновщик же, собирая программу из объектных файлов, проверяет атрибуты выравнивания для каждого файла. Если окажется, что некий файл требует 8-байтового выравнивания стека, а входящие в его состав подпрограммы вызываются из файла, не гарантирующего такое выравнивание, он выдаст ошибку и откажется собирать программу. Таким путём обеспечивается контроль правильности выравнивания стека -- ну а нужно ли оно реально, решать программисту и компилятору (например, если при трансляции программы последний не использует команды, требующие 8-байтового выравнивания, то протранслированному модулю таковое и не требуется).
Каждый выделяемый элемент кучи также должен быть выровнен на границу 8 байтов, поскольку заранее нельзя сказать, как он будет использоваться: а вдруг к нему будут обращаться команды, требующие такого выравнивания? Кроме того, возможна (и нередко вполне целесообразна) такая схема хранения списка свободных участков кучи, когда этот список хранится в самих свободных участках: есть некая переменная, в которой лежит адрес первого свободного участка; в начале каждого участка располагается заголовок из двух полей, содержащий адрес следующего свободного участка и длину текущего свободного участка. На 32-разрядной машине каждая из этих величин имеет размер 32 бита, что в сумме даёт длину заголовка 8 байт -- а это ограничивает минимальный размер каждого свободного участка кучи 8 байтами, а заодно намекает на естественность их выравнивания на границу 8 байтов и выделения кусками, кратными по длине 8 байтам независимо от того, какая длина реально запрошена. По этой причине, если выделять, скажем, память из кучи кусочками по 3 байта, реально будет каждый раз выделяться 8 байт -- и куча будет израсходована намного быстрей, чем можно ожидать лишь на основе её объёма и длины выделяемых блоков.
Что же до разрядности, то 32-разрядные регистры общего назначения никак не отменяют возможности доступа к 64-разрядным данным. Во-первых, есть команды загрузки/сохранения пары регистров общего назначения (LDRD/STRD), которые могут требовать 8-байтового выравнивания (а могут и не требовать -- зависит от состояния какого-там бита в каком-то из управляющих регистров, насколько помню). Во-вторых, у сопроцессора с плавающей запятой (FPU) регистры в общем случае 64-разрядные, поскольку он должен уметь работать не только с 32-разрядными, но и с 64-разрядными числами с плавающей запятой (правда, такой сопроцессор мало где имеется: с ядрами Cortex-M4 интегрирован сопроцессор, поддерживающий лишь 32-разрядную вещественную арифметику, другие ядра серии Cortex-M, как и очень многие процессоры и микроконтроллеры предыдущих версий архитектуры, FPU часто вообще не имеют, и лишь у Cortex-A вроде бы у всех есть FPU с арифметикой двойной точности). Наконец, даже при принципиальной работоспособности без выравнивания на 8-байтовую границу (и вообще без выравнивания) правильное выравнивание обычно способствует повышению производительности. Например, та же команда LDRD, загружающая из памяти пару регистров общего назначения, т.е. два 32-разрядных слова, может выполняться заметно медленнее, если эта пара слов не выровнена на 8-байтовую границу: в такой ситуации одно слово может оказаться в одной строке кэша, а второе -- в другой строке или же вообще в кэше отсутствовать, что потребует считывания его из ОЗУ, и всё это время процессор будет стоять. Понятно, что подобные тормоза из-за нарушения выравнивания характерны в первую очередь для высокопроизводительных процессоров (ядра Cortex-A, а не сравнительно медленные Cortex-M, не имеющие широких внутренних шин, многоуровневой кэш-памяти и т.д. и т.п.), но требования-то пишутся для общего случая, а не для частного.