We have this simple c modified code from stack overflow called funcptrtest.c:
include <stdio.h>
/* C code for program funcptrtest.c
=> https://pastebin.com/rUtXfgSG
*/
const int b = 23;
// A normal function with an int parameter and void return type
void fun(int a)
{
if (a < b)
printf("Value of a (%d) is lesser then value of b (%d)\n", a, b);
else if (a == b)
printf("Value of a (%d) is equal value of b (%d)\n", a, b);
else if (a > b)
printf("Value of a (%d) is greater than value of b (%d)\n", a, b);
}
// main => NO KNR style int main(argc, argv) int argc; char **argv
int main(int argc, char **argv)
{
int i = 0;
/* fun_ptr is a pointer to function fun()
void (*fun_ptr)(int) = &fun;
is equivalent of following two
void (*fun_ptr)(int);
fun_ptr = &fun;
*/
void (*fun_ptr)(int) = &fun;
// call once with static int
(*fun_ptr)(b);
// iterate through for loop
for (i = 1; i < 101; i+=11) {
// Invoking fun() using fun_ptr
(*fun_ptr)(i);
}
return 0;
}
We compile it now with gnu c compiler with gcc option -S and generate an assembler file:
gcc -S funcptrtest.c -o funcptrtest.asm
Result will be something like this:
.file "funcptrtest.c"
.text
.globl b
.section .rodata
.align 4
.type b, @object
.size b, 4
b:
.long 23
.align 8
.LC0:
.string "Value of a (%d) is lesser then value of b (%d)\n"
.align 8
.LC1:
.string "Value of a (%d) is equal value of b (%d)\n"
.align 8
.LC2:
.string "Value of a (%d) is greater than value of b (%d)\n"
.text
.globl fun
.type fun, @function
fun:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movl $23, %eax
cmpl %eax, -4(%rbp)
jge .L2.L2:
movl $23, %eax
cmpl %eax, -4(%rbp)
jne .L4
movl $23, %edx
movl -4(%rbp), %eax
movl %eax, %esi
leaq .LC1(%rip), %rax
movq %rax, %rdi
movl $0, %eax
call printf@PLT
jmp .L5
.L2:
movl $23, %eax
cmpl %eax, -4(%rbp)
jne .L4
movl $23, %edx
movl -4(%rbp), %eax
movl %eax, %esi
leaq .LC1(%rip), %rax
movq %rax, %rdi
movl $0, %eax
call printf@PLT
.L2:
movl $23, %eax
cmpl %eax, -4(%rbp)
jne .L4
movl $23, %edx
movl -4(%rbp), %eax
movl %eax, %esi
leaq .LC1(%rip), %rax
movq %rax, %rdi
movl $0, %eax
call printf@PLT
jmp .L5
.L4:
movl $23, %eax
cmpl %eax, -4(%rbp)
jle .L5
movl $23, %edx
movl -4(%rbp), %eax
movl %eax, %esi
leaq .LC2(%rip), %rax
movq %rax, %rdi
movl $0, %eax
call printf@PLT
.L5:
nop
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size fun, .-fun
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movq %rsi, -32(%rbp)
movl $0, -12(%rbp)
leaq fun(%rip), %rax
movq %rax, -8(%rbp)
movl $23, %edx
movq -8(%rbp), %rax
movl %edx, %edi
call *%rax
movl $1, -12(%rbp)
jmp .L7
.L8:
movl -12(%rbp), %eax
movq -8(%rbp), %rdx
movl %eax, %edi
call *%rdx
addl $11, -12(%rbp)
.L7:
cmpl $100, -12(%rbp)
jle .L8
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0"
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
Lets look, if a simple loop is faster than a function pointer delegate call:
/* program looptest.c */
include <stdio.h>
const int b = 23;
// main
int main(int argc, char **argv)
{
int i = 0;
int a = 23;
/*
if (a < b)
printf("Value of a (%d) is lesser then value of b (%d)\n", a, b);
else if (a == b)
printf("Value of a (%d) is equal value of b (%d)\n", a, b);
else if (a > b)
printf("Value of a (%d) is greater than value of b (%d)\n", a, b);
*/
// iterate through for loop
for (i = 1; i < 4194304; i+=11) {
a = i;
if (a < b)
printf("Value of a (%d) is lesser then value of b (%d)\n", a, b);
else if (a == b)
printf("Value of a (%d) is equal value of b (%d)\n", a, b);
else if (a > b)
printf("Value of a (%d) is greater than value of b (%d)\n", a, b);
}
return 0;
}
/* program funcptrtest.c */
include <stdio.h>
const int b = 23;
// A normal function with an int parameter and void return type
void fun(int a)
{
if (a < b)
printf("Value of a (%d) is lesser then value of b (%d)\n", a, b);
else if (a == b)
printf("Value of a (%d) is equal value of b (%d)\n", a, b);
else if (a > b)
printf("Value of a (%d) is greater than value of b (%d)\n", a, b);
}
// main
int main(int argc, char **argv)
{
int i = 0;
/* fun_ptr is a pointer to function fun()
void (*fun_ptr)(int) = &fun;
is equivalent of following two
void (*fun_ptr)(int);
fun_ptr = &fun;
*/
void (*fun_ptr)(int) = &fun;
// call once with static int
// (*fun_ptr)(b);
// iterate through for loop
for (i = 1; i < 4194304; i+=11) {
// Invoking fun() using fun_ptr
(*fun_ptr)(i);
}
return 0;
}
Well, that's not so deterministic, of course our simple looptest.asm has a shorter assembler.
But execution time is not so huge difference, we have to simulate, that in many scenarios.
[To be continued ...]