В первом случае все значения идут подряд, поэтому компилятор оптимизирует переход по загрузке относительного смещения из таблицы. В thumb-2 для этого используется специальная инструкция: TBH. В ARM возможна прямая адресация регистра PC: LDR PC, [R_TABLE, R_OFFSET, LSL #2]. Для thumb(1) использовался небольшой хак в виде джампа на армовскую процедуру. Теоретически что-то подобное есть для x86, но там я не ковырял - не интересно.
Во втором случае дырки получаются очень большими, чтобы использовать заглушки в таблице, поэтому весь код распадается на 40 сравнений и переходов по >, <, =. Ответ по эффективности очевиден.
void svc(unsigned int num, unsigned int param1, unsigned int param2, unsigned int param3)
{
8000574: b570 push {r4, r5, r6, lr}
8000576: 460e mov r6, r1
disable_interrupts();
8000578: b672 cpsid i
++__KERNEL->svc_count;
800057a: 2420 movs r4, #32
800057c: f2c2 0400 movt r4, #8192 ; 0x2000
8000580: 6ba5 ldr r5, [r4, #56] ; 0x38
8000582: 3501 adds r5, #1
8000584: 63a5 str r5, [r4, #56] ; 0x38
switch (num)
{
default:
8000586: 2827 cmp r0, #39 ; 0x27
8000588: f200 8193 bhi.w 80008b2 svc+0x33e
not default:
800058c: e8df f010 tbh [pc, r0, lsl #1] <-- здесь загружаем в PC значение из таблице. PC += 4 + table_value * 2
8000590: 017f0188 .word 0x017f0188 <-- 0x188, 0x17f, ...
8000594: 016d0176 .word 0x016d0176
8000598: 015c0164 .word 0x015c0164
800059c: 014b0152 .word 0x014b0152
80005a0: 013a0144 .word 0x013a0144
80005a4: 012a0132 .word 0x012a0132
80005a8: 011c0123 .word 0x011c0123
80005ac: 010b0113 .word 0x010b0113
80005b0: 00f80101 .word 0x00f80101
80005b4: 00e600ef .word 0x00e600ef
80005b8: 00d500de .word 0x00d500de
80005bc: 00c300cc .word 0x00c300cc
80005c0: 00b100bb .word 0x00b100bb
80005c4: 009f00a7 .word 0x009f00a7
80005c8: 008d0097 .word 0x008d0097
80005cc: 007a0083 .word 0x007a0083
80005d0: 006a0072 .word 0x006a0072
80005d4: 00590061 .word 0x00590061
80005d8: 00280051 .word 0x00280051
80005dc: 0033003a .word 0x0033003a
Правильно ответил лишь