Open
Description
Clang source-level instrumentation (the -fprofile-instr-generate
option) does not honor the function attribute naked
and generates a prologue that might interfere with the function body. For example, the following code
extern "C" __attribute__((naked))
void semihost(unsigned op __attribute__((unused)),
unsigned int* c __attribute__((unused))) {
__asm(
"PUSH {R4, LR} \n"
"SVC #0xab \n"
"POP {R4, PC} \n"
);
}
When compiled with the current trunk build of Clang, using the flags -target arm-none-eabi -march=armv8-a -O -fprofile-instr-generate
produces the following LLVM IR for the function semihost
:
define dso_local void @semihost(i32 noundef %0, ptr noundef %1) #0 {
%3 = load i64, ptr @__profc_semihost, align 8
%4 = add i64 %3, 1
store i64 %4, ptr @__profc_semihost, align 8
tail call void asm sideeffect "PUSH {R4, LR} \0ASVC #0xab \0APOP {R4, PC} \0A", ""() #1
unreachable
}
Which, in turn, gets compiled into the following assembly:
semihost:
movw r0, :lower16:.L__profc_semihost
movt r0, :upper16:.L__profc_semihost
ldrd r2, r3, [r0]
adds r2, r2, #1
adc r3, r3, #0
strd r2, r3, [r0]
push {r4, lr}
svc #171
pop {r4, pc}
This is incorrect because the function parameters are passed in the registers r0 and r1, and they get overwritten.
I think the correct behavior would be not to instrument naked functions, similarly to how it is done for IR-level coverage: #108552