Yeah, "X" means anything, it should be used only if you don't reference the operand in the asm pattern at all. The usual use case for "X" is if you need e.g. a scratch register in one alternative, but not in another one, so you use e.g. =r when you need it and =X if you don't.
"i" indeed covers non-symbolic as well as symbolic constants, might not work with e.g. -fpic if a PIC base needs to be added, but for -fpic this technique will not really work anyway.
Created attachment 1522612 [details] original file gcc9 fails on this inline asm snippet in the kernel: static inline bool arch_static_branch(struct static_key *key, bool branch) { asm_volatile_goto("0: brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n" ".pushsection __jump_table,\"aw\"\n" ".balign 8\n" ".long 0b-.,%l[label]-.\n" ".quad %c0-.\n" ".popsection\n" : : "X" (&((char *)key)[branch]) : : label); return false; label: return true; } BUILDSTDERR: ./arch/s390/include/asm/jump_label.h: Assembler messages: BUILDSTDERR: ./arch/s390/include/asm/jump_label.h:23: Error: bad expression BUILDSTDERR: ./arch/s390/include/asm/jump_label.h:23: Error: junk at end of line, first unrecognized character is `r' BUILDSTDERR: make[1]: *** [scripts/Makefile.build:277: init/main.o] Error 1 This seems to be from this block: static int __init initcall_blacklist(char *str) { char *str_entry; struct blacklist_entry *entry; /* str argument is a comma-separated list of functions */ do { str_entry = strsep(&str, ","); if (str_entry) { pr_debug("blacklisting initcall %s\n", str_entry); entry = memblock_alloc(sizeof(*entry), SMP_CACHE_BYTES); entry->buf = memblock_alloc(strlen(str_entry) + 1, SMP_CACHE_BYTES); strcpy(entry->buf, str_entry); list_add(&entry->next, &blacklisted_initcalls); } } while (str_entry); return 0; } specifically, the strsep. # 19 "./arch/s390/include/asm/jump_label.h" 1 0: brcl 0,2 .pushsection __jump_table,"aw" .balign 8 .long 0b-.,.L249-. # .quad %r10-. # tmp98 .popsection This looks like the bad assembly, it's generating a referenece to a register.