Informando clang que assembly embutido lê uma região específica da memória
O GCC (todas as versões que posso testar convenientemente) pode ser informado de que uma instrução de montagem em linha lê uma região específica da memória (expressa como um ponteirop
e um tamanhon
) com esse construto reconhecidamente estranho:
asm ("..." : : "m" (*(struct { char x[n]; } *)p));
No entanto, isso não funciona no clang (3. [45]), você recebe um erro grave:
error: fields must have a constant size: 'variable
length array in structure' extension will never be supported
asm ("..." : : "m" (*(struct {char x[n];} *)p));
^
Existe (idealmente) uma construção diferente que produzirá o mesmo efeito nos dois compiladores, ou (na sua falta) uma construção diferente que produzirá o mesmo efeito apenas no clang?
Observe que, no caso em que me preocupo, não insiro instruções reais de montagem; o objetivo da construção é direcionar o compilador para não excluir um aparentemente mortomemset
. Assim, a "construção diferente" poderia perfeitamente não envolver montagem em linha. No entanto, sugira construções que lêemarbitrário memória ou gerar código adicional, apenas se não houver alternativa. Além disso, NÃO sugiramemset_s
, explicit_bzero
, ou similar; esta é uma tentativa deimplemento um fallback para essas funções sem precisar hackear o compilador.
O programa de demonstração em grande escala segue -
#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));
}
- conforme compilado pelo gcc 5.0 em-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
- o objetivo é obter omesmo número de memória de bloco preenche o clang. Dois estão errados, mas quatro também estão errados.