Главная » Ядро Linux » Порядок следования байтов

0

 (byte ordering) — это порядок, согласно которому байты расположены в машинном слове.  Для  разных  процессоров может  использоваться один  из двух типов  нумерации байтов  в машинном слове:  наименее значимый (самый  младший) байт  является либо  самым  первым   (самым левым, left-most), либо самым  последним (самым правым, right-most) в слове.  Порядок байтов  называется обратным (big-endian), если наиболее значимый (самый старший) байт хранится первым, а за ним  идут байты  в порядке убывания значимости. Порядок байтов  называется прямым (little-endian), если наименее значимый (самый младший) байт хранится первым, а за ним  следуют байты  в порядке возрастания значимости.

Даже не пытайтесь основываться на каких-либо предположениях о порядке следования байтов  при  написании кода ядра  (конечно, если  код не предназначен для какой-либо конкретной аппаратной платформы). Операционная система  Linux поддерживает  аппаратные платформы с обоими порядками байтов, включая и те машины, на которых  используемый порядок байтов  можно  сконфигурировать на этапе  загрузки  системы, а общий код должен  быть совместим с любым  порядком байтов.

На  рис.  19.1  показан пример обратного порядка следования байтов, а на рис. 19.2 — прямого порядка следования байтов.

Аппаратная платформа i386 использует прямой  (little-endian)  порядок байтов. Большинство других аппаратных платформ обычно  использует обратный (big-endian) порядок.

5 Если бы компилятор имел  возможность изменят ь порядо к следования  ноле й структуры  данных,  то любой  существующий   код,  которы й уже использует  эту структуру,  мог бы  испортить  данные.  В языке  программирования  С  функции вычисляют  положение полей  прост о путем  введения  смещений от начального   адреса  структуры  в  памяти.

Номер байта

0     1    2    3

Старший байт

Младший байт

Рис.  19.1.   Обратный  (big-endian)   порядок  следования  байтов

Номер байта

3     2     1    О

Старший байт

Младший байт

Рис.  19.2.  Прямей  (little-endian)   порядок  следования  байтов

Рассмотрим, что эти типы  кодирования обозначают на практике и как  выглядит двоичное представление числа  1027, которое  хранится в виде  четырехбайтового целочисленного типа данных.

00000000 00000000 00000100 00000011

Внутренние представления этого  числа  в памяти при  использовании прямого и обратного порядка байтов  отличаются, как это показано в табл. 19.3.

Таблица 19.3. Расположение данных в памяти для разных порядков  следования  байтов

Адрес

Обратный порядок

Прямой порядок

0

00000000

00000011

1

00000000

00000100

2

00000100

00000000

3

00000011

00000000

Обратите внимание на то, что для аппаратной платформы с обратным порядком байтов  самый  старший байт записывается в самый  минимальный адрес памяти.

И наконец, еще один  пример — фрагмент кода, который позволяет определить порядок байтов для той аппаратной платформы, на которой он выполняется.

int х = 1;

if (*(char *)&х == 1)

/* прямой порядок */

else

/* обратный порядок */

Этот пример работает  как в ядре, так и в пространстве пользователя.

История терминов big-endian и little-endian

Термин ы  big-endian  и  little-endian   заимствован ы  из  сатирическог о  роман а Джонатана  Свифта  "Путешествие  Гулливера",  который  был издан  в  1726 году. В этом романс  наиболее  важной  политической   проблемой  народа  лилипутов  была проблема,  с какого  конца  следует разбивать  яйцо:  с тупого  (big) или  острого  (little).  Тех, кто предпочитал  тупой конец  называли  "тупоконечниками"   (big-endian),  тех же,  кто предпочитал  острый  конец,  называли  "остроконечниками"  (little-endian).

Аналогия  между дебатами лилипутов  и спорами  о том,  какой  порядок  байтов лучше,  говорит о том,  что это вопрос  больше  политический, чем технический.

Порядок байтов в ядре

Для  каждой  аппаратной   платформы,   которая  поддерживается  ядром  Linux,  в файле  <asm/byteorder.h >  определена  одна  из  двух констант       BIG_ENDIAN  или

    LITTLE_ENDIAN, в соответствии  с используемым  порядком  байтов.

В  этот  заголовочный   файл  также  включаются  макросы  из  каталога  include / linux/byteorder/ ,  которые  помогают  конвертировать  один  порядок  байтов  в другой.  Ниже  показаны  наиболее  часто используемые  макросы.

u23  cpu_to_be32(u32); /* преобразовать порядок байтов текущего процессора в порядок big-endian */

u32  cpu_to_le32(u32); /* преобразовать порядок байтов текущего процессора в порядок little-endian */

u32  be32_to_cpu(u32);  /* преобразовать порядок байтов big-endian в

порядок байтов текущего процессора */

u32  lе32_to_cpus(u32); /* преобразовать порядок байтов little-endian в порядок байтов текущего процессора */

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

Таймер

Никогда  нельзя  привязываться  к какой-либо конкретной частоте  генерации  прерывания  системного  таймера и,  соответственно,  к тому,  сколько  раз в секунду изменяется   переменная   jiffies .  Всегда  необходимо  использовать  константу HZ, чтобы корректно  определять  интервалы  времени.  Это  очень важно,  потому что значение частоты  системного  таймера  может  отличаться  не  только  для  разных  аппаратных платформ,  но  и для одной  аппаратной   платформы  при  использовании разных версий ядра.

Например, константа  HZ  для аппаратной  платформы  х86 сейчас равна  1000. Это значит,  что прерывание  таймера  возникает  1000 раз в секунду,  или  каждую миллисекунду. Однако  до серии  ядер 2.6 для аппаратной  платформы  х86 значение  константы HZ  было равно  100. Для разных аппаратных платформ  эти значения  отличаются:  для аппаратной  платформы  alpha константа  HZ  равна 1024, а для платформы  ARM — 100.

Никогда нельзя  сравнивать значение переменной  jiffie s  с  числом, таким  как

1000,  и думать,  что это всегда будет означать  одно  и то же. Для получения интервалов времени необходимо всегда умножать  или делить  на константу HZ,  как в следующем примере.

HZ            /* одна секунда */ (2*HZ)        /* две секунды */ (HZ/2)        /* полсекунды  */ (HZ/100)      /* 10 мс */ (2*Н2/100)   /*  20 мс */

Константа HZ  определена п файле <asm/param.h>. Об этом подробно рассказано в главе 10, "Таймеры  и упрадление временем".

Источник: Лав,  Роберт. Разработка ядра  Linux, 2-е  издание. : Пер.  с англ.  — М.  : ООО  «И.Д.  Вильяме» 2006. — 448 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии