Skip to content

Commit

Permalink
Point to tty demo
Browse files Browse the repository at this point in the history
  • Loading branch information
robertdfrench committed Jul 19, 2024
1 parent 93cc708 commit adaff08
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 4 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,26 @@ can adapt your work to my needs without having to bother you about it. But it
can also lead to a degree of indirection that prevents critical design
assumptions (such as a traditional dynamic linking process) from being upheld.


## What does GNU IFUNC even do?
It allows you to determine, at runtime, which version of some function you'd
like to use.
like to use. It does this by allowing you to run **arbitrary code** to
influence how the linker resolves symbols.

![](memes/ifunc_hard_right.png)

Suppose you have one application that must run on a wide variety of x86 CPUs.
Depending on the specific features of the current CPU, you may prefer to use
different algorithms for the same task. The idea behind IFUNC was to allow
programs to check for CPU features the first time a function is called, and
thereafter use an implementation that will be most appropriate for that CPU.

Take a look at [`tty_demo.c`](src/tty_demo.c) for an example. This is a
toy program that prints "Hello World!" when its stdout is a file, but
prints that message using green text if its output is a terminal. It
uses IFUNC to load the appropriate implementation when the program
starts.

Unfortunately, IFUNC can be used for other purposes, as Sam James explains in
[FAQ on the xz-utils backdoor (CVE-2024-3094)][thesamesam].

Expand Down
14 changes: 11 additions & 3 deletions src/tty_demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,22 @@ void print_to_file(const char *message) {
printf("FILE: %s\n", message);
}

// IFUNC attribute to use the resolver. This tells the compiler to use the
// "resolve_print_function" function to determine which function to call when
// the "print_message" function is called. It's only goofy the first time!
// This is how you declare an IFUNC.
//
// This attribute tells gcc to invoke the "resolve_print_function" function
// during the link phase in order to determine which implementation of
// "print_message" should be used.
void print_message(const char *message) __attribute__((ifunc("resolve_print_function")));

// Resolver function
//
// This function returns a function pointer to the implementation we'd like to
// use for "print_message".
void (*resolve_print_function(void))(const char *) {
struct termios term;

// Calling another dynamic function inside the resolver might not be safe in
// general, but this example is very silly anyhow.
int result = ioctl(STDOUT_FILENO, TCGETS, &term);
if (result == 0) {
// stdout is a terminal
Expand Down

0 comments on commit adaff08

Please sign in to comment.