вторник, 9 декабря 2008 г.

ia64 - неверное объявление данных near и far

Это перевод ia64 - misdeclaring near and far data. Автор: Реймонд Чен.

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

В ia64 нет режима абсолютной адресации. Вместо этого вы обращаетесь к своим глобальным данным через регистр r1, который имеет псевдоним "gp" (global pointer - глобальный указатель). Этот регистр всегда указывает на ваши глобальные переменные. Например, если у вас есть три глобальные переменные, то одна из них может лежать по адресу [gp+0], вторая по [gp+8], а третья - [gp+16].

(Мне кажется, что соглашение вызова на Win32 MIPS также использовало такую технику).

На ia64 есть также ограничение инструкции "addl": вы можете прибавлять константы только размером меньше 22-х битов, что равно 4 Мб. Поэтому вы можете иметь только 4 Мб глобальных переменных.

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

Компилятор ia64 решает эту проблему разделением глобальных переменных по двум категориям: "маленькие" и "большие" (граница между категориями может устанавливаться флагом компилятора. Я думаю, что значение по-умолчанию рассматривало любые данные размером больше 8-ми байт как большие).

Код для доступа к "маленьким" данным получается таким:
        addl    r30 = -205584, gp;; // r30 -> глобальную переменную
ld4 r30 = [r30] // загрузить значение DWORD из глоабльной переменной
(Регистр gp на самом деле указывает в середину ваших глобальных данных, так что можно использовать и положительные и отрицательные смещения. В нашем случае переменная живёт по отрицательному смещению от gp).

Сравним это с двухшаговым доступом к "большим" переменным. Сначала сама переменная должна быть найдена в отдельной секции файла. Затем указатель на переменную копируется в область для "маленьких" глобальных переменных. В результате доступ к "большим" глобальным переменным добавляет ещё один слой адресации:
        addl    r30 = -205584, gp;; // r30 -> указатель на глобальную переменную
ld8 r30 = [r30];; // r30 -> глобальную переменную
ld4 r30 = [r30] // загружает значение DWORD из глобальной переменной
Если вы не станете указывать размер объекта, как, например
extern BYTE b[];
то тогда компилятор решит перестраховаться и предполагает, что переменная - "большая". Если окажется, что переменная на самом деле маленькая, то дополнительный указатель всё равно будет доступен, и коду программы придётся делать три шага для доступа к переменной, которая могла бы быть доступна в две инструкции. Код получится чуть менее эффективным, но по крайней мере он будет работать.

С другой стороны, если вы неверно объявите объект как маленький, когда он в действительности большой, то тогда у вас будут неприятности. Например, если вы напишете
    extern BYTE b;
в одном файле и
    extern BYTE b[256];
в другом, то тогда файлы, которые включают в себя первое объявление будут думать, что объект - "маленький" и генерировать две инструкции для доступа, а файлы, которые включают в себя первое объявление, будут считать этот объект большим. И если в итоге объект окажется всё же большим, то код, который использовал первое объявление, будет весьма впечатляюще вылетать.

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

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.