Storing "blockaddress(@function, %block)" in a global variable?


The LangRef warns that “blockaddress(@function, %block)” has a limited and target-dependent applicability:

But I wanted very much to save addresses of blocks in a global variable and so I did:

% cat cond.c
void foo(long *a) { if (a) *a = 0; }

% clang -O1 -c cond.c -fsanitize-coverage=inline-8bit-counters,pc-table -S -o - -emit-llvm

@_sancov_gen.1 = private constant [3 x i8*] [i8* bitcast (void (i64*)* @foo to i8*), i8* blockaddress(@foo, %entry.if.end_crit_edge), i8* blockaddress(@foo, %if.then)], section “__sancov_pcs”, align 8

Is this expected to work?
If not, is it reasonable to try to make it work?

This works almost as I want it to, but not quite entirely:
% cat cout.cpp

void Foo() { std::cout << “”; }

% clang++ -fsanitize-coverage=inline-8bit-counters,pc-table cout.cpp -O1

fatal error: error in backend: Undefined temporary symbol

(the error message was added in by Oliver Sstannard, CC-ed)

The error comes from lib/MC/ELFObjectWriter.cpp
and it disappears with -O0 or -O2 or -no-integrated-as



I think I would expect this to work in general for ELF targets, as long as both the global variable and the function are either not comdat members or members of the same comdat.

If I compile your example to .ll I get:

@_sancov_gen.5 = private constant [3 x i8*] [i8* bitcast (%“class.std::basic_ostream”* (%“class.std::basic_ostream”*, i8*)* @_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc to i8*), i8* blockaddress(@_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc, %if.then), i8* blockaddress(@_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc, %if.else)], section “__sancov_pcs”, align 8

and later:

define available_externally dereferenceable(272) %“class.std::basic_ostream”* @_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc(%“class.std::basic_ostream”* dereferenceable(272) %__out, i8* %__s) local_unnamed_addr #3 {


The initializer is referencing a function with available_externally linkage, which I wouldn’t expect to work because the object file will not contain a definition of the function. If I create a .s file from your example and remove the definition of _sancov_gen.5 I can produce an object file using llvm-mc.

So I would probably try changing the instrumentation pass to skip available_externally functions.


Yes, indeed, thanks Peter!
In fact, asan already rejects available_externally functions, for a similar reason.