user2862654
user2862654

Reputation: 65

Calling printf() by its pointer

Everything works:

#include <stdio.h>

int (* func)(const char * fmt, ...);

int main()
{
  func = (void *)0x400420; /* printf pointer */
  printf("printf address: %p\n", printf);
  func("func() calling\n");
  return 0;
}

But this does not work:

#include <stdio.h>

int (* func)(const char * fmt, ...);

int main()
{
  func = (void *)0x400420; /* printf pointer */
  /* printf("printf address: %p\n", printf); */
  func("func() calling\n");
  return 0;
}

Whats I am doing wrong? Tell me, please. Can I call printf (or some other function) by its pointer?

Upvotes: 4

Views: 965

Answers (4)

Bogus Bogus
Bogus Bogus

Reputation: 3

on windows 7, compiler: mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0

int main()
{
    int c = 5;
    int (*pr)(const char *const _Format, ...);
    pr = &printf;
    (*pr)("%d\n", c);
    
    return 0;
}

compiles and runs. you can follow the instructions in this video Pointers in C / C++ [Full Course] to get a better understanding. Around the 3 hour mark, the instructor starts talking about function pointers.

Upvotes: 0

Art
Art

Reputation: 20392

Two possibilites (which actually have the same primary cause):

  1. You're doing static linking. This would mean that the linker doesn't need to pull in printf from libc, so printf doesn't get linked into your program at all.

  2. You're doing dynamic linking, but on your architecture function pointers don't actually point to the function itself, but its dynamic trampoline. This means that the magic pointer you found is to a trampoline that only got created because you actually called printf from your program.

I'm pretty sure you're dynamically linking. Let's see how this works in practice with this simple program:

#include <stdio.h>

int
main(int argc, char **argv)
{
    void *foo = (void *)printf;
    return 0;
}

We compile and link this, and then disassemble. This is the relevant instruction that loads the address of printf into a local variable.

  4004cf:       48 c7 45 f8 c0 03 40    movq   $0x4003c0,-0x8(%rbp)

Notice that the pointer is 0x4003c0 which quite similar to what your pointer was. But wait a second. The address of this instruction is 0x4004cf. This is awfully close to where the printf pointer points, in fact it's in the same page, so it's impossible that this is a pointer to libc. Let's see what's at that address:

00000000004003c0 <printf@plt>:
  4003c0:       ff 25 92 04 20 00       jmpq   *0x200492(%rip)
  4003c6:       68 00 00 00 00          pushq  $0x0
  4003cb:       e9 e0 ff ff ff          jmpq   4003b0 <_init+0x18>

This is part of the program, not libc. If you change the program to call printf, it will actually jump to this address. This is the dynamic trampoline I was talking about. "plt" here stands for Procedure Linkage Table and it's the magic that the dynamic linker uses to be able to resolve function calls without modifying the text segment of your program.

Your problem is that you removed any link to printf in your program. Since it's not there, the linker will not generate this trampoline and you just set your pointer to point to something random that happened to be generated at that address.

Btw. Actually referencing printf in your program won't be enough to make tricks like this work. It's likely that calling just one other function will put PLT entries for that function at the same place that the trampoline for printf was generated. You're definitely not guaranteed where those trampolines end up and in my experience with how linkers generate code it will be seemingly random (because ordering of PLT entries is affected by ordering of internal hash tables in the linker). In other words, this only has a decent chance to work when your program looks exactly like the program that you used to print the address.

Upvotes: 3

Mauren
Mauren

Reputation: 1975

Change your code to evaluate printf address instead of putting it fixed:

#include <stdio.h>

int (* func)(const char * fmt, ...);

int main()
{
    func = printf; /* printf pointer */
    func("func() calling\n");
    return 0;
}

Upvotes: 3

CS Pei
CS Pei

Reputation: 11047

In the second example, printf is not linked to your program.

Upvotes: 8

Related Questions