How does LLVM know where to resolve declared only functions?

Hi

In the generated .ll file, it may have something like this. How does
LLVM know where to look for the definition of printf? Is it documented
somewhere? Thanks.

declare i32 @printf(i8*, ...) #1

It’s the linkers job to hook together functions and definitions that end up in the same binary. Your OS will then hook in functions from other binaries when your executable is loaded into memory.

It's the linkers job to hook together functions and definitions that end up in the same binary. Your OS will then hook in functions from other binaries when your executable is loaded into memory.

How does it know whether it is a system function or a user-defined function?

It seems that user functions have higher priorities over system
functions as demonstrated by the following example.

Is there any way to always use system functions for certain function
calls (but not always default to system functions) when there are
local functions with the same name?

==> main.c <==
/* vim: set noexpandtab tabstop=2: */
#include <stdio.h>

int main() {
    puts("Hello World!");
    return 0;
}

==> myputs.c <==
/* vim: set noexpandtab tabstop=2: */
#include <stdio.h>

int myputs(char *s) {
    return printf("myputs:%s\n", s);
}

$ ./main1.sh
clang -Wall -pedantic -S -emit-llvm -c -o main.ll main.c
clang -Wall -pedantic -S -emit-llvm -c -o myputs.ll myputs.c
clang -Wall -pedantic -c -o main.o main.ll
clang -Wall -pedantic -c -o myputs.o myputs.ll
clang main.o myputs.o -o ./main.exe
./main.exe
Hello World!
sed -i 's/@myputs\>/@puts/g' myputs.ll
clang -Wall -pedantic -c -o myputs.o myputs.ll
clang main.o myputs.o -o ./main.exe
./main.exe
myputs:Hello World!

$ cat ./main1.sh
#!/usr/bin/env bash
# vim: set noexpandtab tabstop=2:

set -v
clang -Wall -pedantic -S -emit-llvm -c -o main.ll main.c
clang -Wall -pedantic -S -emit-llvm -c -o myputs.ll myputs.c
clang -Wall -pedantic -c -o main.o main.ll
clang -Wall -pedantic -c -o myputs.o myputs.ll
clang main.o myputs.o -o ./main.exe
./main.exe
sed -i 's/@myputs\>/@puts/g' myputs.ll
clang -Wall -pedantic -c -o myputs.o myputs.ll
clang main.o myputs.o -o ./main.exe
./main.exe

Note, I’m using a linux system.

It’s the linkers job to hook together functions and definitions that end up in the same binary. Your OS will then hook in functions from other binaries when your executable is loaded into memory.

How does it know whether it is a system function or a user-defined function?

It seems that user functions have higher priorities over system
functions as demonstrated by the following example.

Is there any way to always use system functions for certain function
calls (but not always default to system functions) when there are
local functions with the same name?

==> main.c <==
/* vim: set noexpandtab tabstop=2: */
#include <stdio.h>

int main() {
puts(“Hello World!”);
return 0;
}

==> myputs.c <==
/* vim: set noexpandtab tabstop=2: */
#include <stdio.h>

int myputs(char *s) {
return printf(“myputs:%s\n”, s);
}

$ ./main1.sh
clang -Wall -pedantic -S -emit-llvm -c -o main.ll main.c
clang -Wall -pedantic -S -emit-llvm -c -o myputs.ll myputs.c
clang -Wall -pedantic -c -o main.o main.ll

objdump -t main.o

0000000000000000 UND 0000000000000000 puts


At this point the .o doesn’t specify where puts should be found.

clang -Wall -pedantic -c -o myputs.o myputs.ll

clang main.o myputs.o -o ./main.exe

objdump -t main.exe

0000000000000000 F UND 0000000000000000 puts@@GLIBC_2.2.5

The linker found puts in glibc. However using LD_PRELOAD you could still link against a different implementation at runtime.

./main.exe
Hello World!
sed -i ‘s/@myputs>/@puts/g’ myputs.ll
clang -Wall -pedantic -c -o myputs.o myputs.ll
clang main.o myputs.o -o ./main.exe

objdump -t main.exe

0000000000000000 F UND 0000000000000000 printf@@GLIBC_2.2.5

No external reference to puts, because it was found during the link step.

At this point the .o doesn't specify where puts should be found.

If the glibc's puts() call a function f() in glibc, and I define
another f() in main.ll, will the f() in main.ll be called by glibc's
puts() or the f() in glibc be called? Thanks.