GCC (all versions I can conveniently test) can be told that an inline assembly statement reads a particular region of memory (expressed as a pointer p
and a size n
) with this admittedly awkward construct:
asm ("..." : : "m" (*(struct { char x[n]; } *)p));
However, this does not work in clang (3.[45]), you get a hard error:
error: fields must have a constant size: 'variable
length array in structure' extension will never be supported
asm ("..." : : "m" (*(struct {char x[n];} *)p));
^
Is there (ideally) a different construct which will produce the same effect in both compilers, or (failing that) a different construct which will produce the same effect in clang, only?
Note that in the case I care about, I insert no actual assembly instructions; the point of the construct is to direct the compiler not to delete an apparently-dead memset
. Thus, the "different construct" could perfectly well not involve inline assembly at all. However, please suggest constructs which read arbitrary memory, or generate additional code, only if there is no alternative. Also, DO NOT suggest memset_s
, explicit_bzero
, or similar; this is an attempt to implement a fallback for those functions without having to hack the compiler.
Full-scale demo program follows --
#include <string.h>
extern void foo(const char *a, const char *b, const char *c, char *d);
void bar(const char *x, char *y, size_t n)
{
char w[16];
char v[n];
memset(w, 0x11, n);
memset(v, 0x22, n);
foo(w, v, x, y);
memset(w, 0, 16);
memset(v, 0, n);
asm ("" : : "m" (*(struct {char _[n];} *)v));
}
-- as compiled by gcc 5.0 at -O2 -S
, x86-64, CFI goo elided --
bar:
pushq %rbp
leaq 15(%rdx), %rax
movq %rsp, %rbp
pushq %r14
andq $-16, %rax
movq %rsi, %r14
pushq %r13
movl $17, %esi
movq %rdi, %r13
pushq %r12
leaq -48(%rbp), %rdi
pushq %rbx
movq %rdx, %rbx
subq $16, %rsp
subq %rax, %rsp
call memset
movq %rbx, %rdx
movq %rsp, %rdi
movl $34, %esi
call memset
movq %r14, %rcx
movq %r13, %rdx
movq %rsp, %rsi
leaq -48(%rbp), %rdi
call foo
movq %rbx, %rdx
xorl %esi, %esi
movq %rsp, %rdi
call memset
leaq -32(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %rbp
ret
-- the goal is to get the same number of block memory fills out of clang. Two is wrong, but four is also wrong.