Мне было любопытно, как выполняются переходы переключения по отношению к вызовам функций, поэтому я сделал быстрый тест:
#!/bin/bash -eu
cat > get.c <<EOF
#include <stdint.h>
int get(int (Getter)(void))
{
uintptr_t getter=(uintptr_t)Getter;
if(1){
switch(getter){
case 0: return $RANDOM;
case 1: return $RANDOM;
case 2: return $RANDOM;
case 3: return $RANDOM;
case 4: return $RANDOM;
case 5: return $RANDOM;
default: return Getter();
}
}else{
if(0==getter) return $RANDOM;
else if(1==getter) return $RANDOM;
else if(2==getter) return $RANDOM;
else if(3==getter) return $RANDOM;
else if(4==getter) return $RANDOM;
else if(5==getter) return $RANDOM;
else return Getter();
}
}
EOF
cat > main.c <<EOF
int get(int (Getter)(void));
int Getter(void){ return 42; }
int main(int C, char**V)
{
if(C==1)
for(int i=0; i<1000000000;i++)
get((int(*)(void))4);
else
for(int i=0; i<1000000000;i++)
get(Getter);
}
EOF
: ${CC:=gcc}
arg='-Os -fpic'
for c in *.c; do $CC $arg -c $c; done
$CC get.o -o libget.so -shared
$CC main.o $PWD/libget.so -o dso
$CC main.o get.o -o dso -o static
set -x
time ./dso
time ./dso 1
time ./static
time ./static 1
Время (относительно стабильное):
+ ./dso
real 0m3.778s
user 0m3.709s
sys 0m0.056s
+ ./dso 1
real 0m3.739s
user 0m3.736s
sys 0m0.000s
+ ./static
real 0m2.478s
user 0m2.477s
sys 0m0.000s
+ ./static 1
real 0m3.425s
user 0m3.411s
sys 0m0.000s
Почемупрыжки переключателя работают немного лучше, но только когда функция связана статически?
Разборка различий (генерируемых sdiff) динамической и статической версий соответственно:
000000000000111a <get>: | 0000000000001180 <get>:
cmp $0xc,%rdi cmp $0xc,%rdi
ja 1178 <get+0x5e> | ja 11de <get+0x5e>
lea 0xed9(%rip),%rdx # 2000 <_fini+0xe80> | lea 0xe77(%rip),%rdx # 2004 <_IO_stdin_used
movslq (%rdx,%rdi,4),%rax movslq (%rdx,%rdi,4),%rax
add %rdx,%rax add %rdx,%rax
jmpq *%rax jmpq *%rax
mov $0x132b,%eax mov $0x132b,%eax
retq retq
mov $0x2740,%eax mov $0x2740,%eax
retq retq
mov $0x79b6,%eax mov $0x79b6,%eax
retq retq
mov $0x5234,%eax mov $0x5234,%eax
retq retq
mov $0x6389,%eax mov $0x6389,%eax
retq retq
mov $0x37de,%eax mov $0x37de,%eax
retq retq
mov $0x6a22,%eax mov $0x6a22,%eax
retq retq
mov $0x1a35,%eax mov $0x1a35,%eax
retq retq
mov $0x2ce8,%eax mov $0x2ce8,%eax
retq retq
mov $0x4fed,%eax mov $0x4fed,%eax
retq retq
mov $0xfe3,%eax mov $0xfe3,%eax
retq retq
mov $0x4229,%eax mov $0x4229,%eax
retq retq
jmpq *%rdi jmpq *%rdi
mov $0x529e,%eax mov $0x529e,%eax
retq retq
<