Compiler emits indirect call through GOT for statically linked extern functions

I noticed that rustc emits indirect function calls to extern functions even for statically linked extern libraries. For example, consider the following code:

use std::os::raw::c_int;

#[link(name = "foo", kind = "static")]
extern "C" {
    fn foo_add(lhs: c_int, rhs: c_int) -> c_int;
}

fn main() {
    let res = unsafe { foo_add(1, 2) };
    println!("{}", res);
}

rustc emits the following code snippet into the final executable file:

0000000000007c30 <_ZN4main4main17h06bd8598508590c8E>:
    7c30:	48 83 ec 48          	sub    $0x48,%rsp
    7c34:	bf 01 00 00 00       	mov    $0x1,%edi
    7c39:	be 02 00 00 00       	mov    $0x2,%esi
    7c3e:	ff 15 a4 4d 04 00    	callq  *0x44da4(%rip)        # 4c9e8 <_GLOBAL_OFFSET_TABLE_+0xd0>

So rustc emits indirect call through GOT at 0x7c3e even if foo_add is linked against statically. Is this behavior intentional? Why don't rustc just emit a plain function call in such a case, as a C/C++ compiler would do?

When compiling the function it is not yet known that the callee would be statically linked. Note that C++ probably makes it a relative rather than a GOT call due to RELRO being disabled by default for C++ while rustc emables it by default. This means that C++ can emit a PLT call which the linker can relax to a relative call while rustc emits a GOT call as the lazy symbol resolving the PLT allows isn't possible with full RELRO anyway due to the GOT being made read-only after relocating.

Are you sure? I haven't heard of relro causing a performance hit besides the actual effort of doing the relocations at startup, which isn't applicable here. And isn't relro only specified at link time anyway?

Perhaps this actually is something to do with ELF interposition support?

Perhaps this actually is something to do with ELF interposition support?

I don't think it is related to ELF interposition since foo_add is statically linked into an ELF executable. AFAIK, symbols in an ELF executable cannot be interpolated.

We disable PLT usage at codegen time when RELRO is enabled.