Skip to content

Instantly share code, notes, and snippets.

@seisvelas
Last active December 25, 2020 08:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seisvelas/e88fe0114c1e10e9f6bf5a4130d94f92 to your computer and use it in GitHub Desktop.
Save seisvelas/e88fe0114c1e10e9f6bf5a4130d94f92 to your computer and use it in GitHub Desktop.
Is a function pointer just the address of the label?
#include <stdio.h>
#include <stdint.h>
/*
Test whether a function pointer is really just
a pointer to the memory location of a label.
Which would make sense, only I never really looked
into function pointers, so I'm curious if this is
what they are.
If this doesn't work, I'll have to actually look it up
(like a little bitch)
*/
int64_t self_label_address(void) {
asm(
"lea rax, QWORD [self_label_address]"
);
}
int main(void) {
int64_t rip = self_label_address();
int64_t function_addr = (int64_t)self_label_address;
printf("RIP, in function: %ld\n", rip);
printf("label address: %ld\n", (long int)self_label_address);
printf("difference: %ld\n", rip - (int64_t)self_label_address);
return 0;
}
@seisvelas
Copy link
Author

alex@fatima-Inspiron-5570:~/Code/Khety$ gcc -O0 -masm=intel fun.c -fno-stack-protector -no-pie -Wint-conversion && ./a.out 
RIP, in function: 4198718
label address:    4198710
difference:       8

So they are 8 bytes apart. In other words, one memory address away (since I'm on 64 bit Linux, an address is 8 bytes). Hmm. Why aren't they identical? From looking up how label addresses work, I think that it's like this:

  • Function pointer points to the address of the label, BUT
  • The label itself is a pointer to the first instruction after the label.

Ie, if you use the label as a pointer, you get something further along than the label's actual location in memory. Here's the function in assembly that the compiler generates:

self_label_address:
.LFB0:
	.cfi_startproc
	endbr64
	push	rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	mov	rbp, rsp
	.cfi_def_cfa_register 6
#APP
# 16 "fun.c" 1
	mov rax, QWORD [self_label_address]
# 0 "" 2
#NO_APP
	nop
	pop	rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc

So I guess [self_label_address] is giving us the address of the endbr64 instruction (since the two things in between are assembler directives, not 'real' instructions that would appear in the machine code). Hmm. This has been very educational!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment