23.03.2006

Трюк со switch/case


Любопытна реализация конструкции switch/case в компиляторе RVCT для процессоров ARM. Довольно специфическая вещь, но, может быть, кому-нибудь пригодится - в качестве примера.
Данный трюк используется при компиляции кода в режиме THUMB. Этот режим используется для получения компактного кода для процессоров ARM.
Итак, условия:

  • конструкция switch/case;

  • ключ switch является целочисленным;

  • значения в case-метках идут "почти" подряд (т.е., возможны пропуски);

  • используется пять и более case-меток.


Пример:

int a;
...
switch (a)
{
case 10:
return 123;
case 11:
return 43;
case 12:
return 12;
case 13:
return 21;
case 15:
return 98;
}
return 1;

В этом случае RVCT генерирует вызов специальной процедуры __ARM_switch8 и сразу после точки вызова - таблицу переходов. Таблица переходов состоит из (n + 2) байтов плюс байт для выравнивания по границе слова (n - число case-меток).
Таблица переходов имеет следующий вид:











СмещениеЗначение
0Число case-меток
1Смещение до первой case-метки
2Смещение до второй case-метки
3Смещение до третьей case-метки
......
nСмещение до n-ой case-метки
n + 1Смещение до default-метки (default-метка может быть неявной)
[n + 2]Дополнение до границы слова (если нужно)


В функцию передается номер case-метки a. После этого выполняются следующие действия:

  1. По адресу [lp] считывается число case-меток n;

  2. Переданный номер case-метки a "обрезается" по отрезку [0..n];

  3. Выполняется переход по адресу, указанному в таблице по индексу a.


lp - адрес возврата из процедуры.
Для приведенного выше примера код выглядит следующим образом (значиние a содержится в регистре r0):

SUBS r0,r0,#0xa
BL __ARM_switch8
DCB 0x06,0x04
DCB 0x06,0x08
DCB 0x0a,
0x0e
DCB 0x0c,0x0e

Красным цветом выделены переходы по неявной default-метке. В частности, такой переход выполняется в случае, если значение a равно 14.

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

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