Re: Specifying different registers in inline asm
jh--- via Gcc-help <[email protected]>
| Newsgroups | gmane.comp.gcc.help |
|---|---|
| Message-ID | <[email protected]> |
Le 2025-11-19 11:18, Richard Earnshaw (foss) a écrit : > On 19/11/2025 08:03, jh--- via Gcc-help wrote: >> Le 2025-11-18 18:10, Segher Boessenkool a écrit : >>> Hi! >>> >>> On Tue, Nov 18, 2025 at 06:01:33PM +0100, [email protected] wrote: >>>> Le 2025-11-18 17:43, Segher Boessenkool a écrit : >>>> > On Tue, Nov 18, 2025 at 11:22:40AM +0100, jh--- via Gcc-help wrote: >>>> > > I am sorry if the answer is trivial, but I couldn't find it. >>>> > > I need to access a specific instruction on ARM, so I used an inline >>>> > > asm >>>> > > block to do it. >>>> > > My problem is that the instruction (LDRBT) reads a byte in a >>>> > > register from >>>> > > an address, but the address is written back to its register as well, >>>> > > so the >>>> > >>>> > If an operand is both read and written, you should inform the compiler >>>> > of that fact. Typically by marking it as "+" (i.e. read/write) output >>>> > constraint. >>>> I tried marking the address parameter with a "+", but since it's not >>>> an >>>> lvalue (I call the macro with &buf[cnt]), it did not work. >>> >>> The first copy it into a variable that *is* writable? This is >>> required >>> for correctness, since your asm *does* modify the reg! >> I'm not sure about this situation, for me there are two sides on this >> matter: a practical one and a theoretical one. >> On the practical side, the instruction does a write back to the >> register, but with the same value (because omission of the offset is >> equal to 0 in this instance), so the register does not change value. >> On a theoretical side, I would like to tell the compiler that the >> register is clobbered, that I don't care about the value anymore, but >> that if the compiler needs the value, it cannot rely on the fact that >> the register still contains it. I think it is not possible to specify >> clobbers for input values, but it makes sense to be able to use a >> non-lvalue here, so I don't want to specify it as an output. Is this >> doable? >> >>>> > > destination and the address register should be different (as helpfully >>>> > > mentioned by the assembler: "destination register same as write-back >>>> > > base"). >>>> > > The code generator produces "LDRBT R3, [R3]" which is not correct. >>>> > > I would like to specify that I want two distinct registers for %0 >>>> > > and %1 (my >>>> > > code is LDRBT %0, [%1]), but I did not find how. >>>> > >>>> > If you want literally what you ask for (but read above), what you want >>>> > is an "earlyclobber". Written as "&", see the manual. >>>> > >>>> Thank you very much, it is so obviously described, once you know >>>> where to >>>> look. >>> >>> As always :-) >>> >>> One thing you can try is "read everything". I've been trying to do >>> that >>> forever now, and am still not done, but making some progress I hope >>> ;-) >> Nah, the real method is to "read everything an infinite number of >> times", because on each pass you understand something that you have >> read before, but which did not click into place. But as everyone knows >> eternity is very long, especially towards the end. >> >>>> > > Could you please tell me what the situation is here (I could make a >>>> > > work-around by moving the result to another register and using the >>>> > > clobber >>>> > > list, but that's inefficient on several scales)? >>>> > > Also, more generally, is this not an issue that could be considered >>>> > > being >>>> > > addressed, maybe by adding to the asm constraints (if it is not yet >>>> > > the >>>> > > case) or by adding it to the documentation (as an example)? >>>> > >>>> > It is a pretty common problem, and that is why it has been handled since >>>> > decades already :-) >>>> We---ell you know, sometimes (most of the times) you think you have >>>> the most >>>> important problem in the world and it's not the case. >>>> Also it IS documented, and I don't really know how it could be any >>>> more >>>> obvious (except maybe as part of a 'cookbook'. Or using AI as RAG, >>>> but who >>>> wants to do that?). >>>> >>>> > Segher >>>> PS.: someone beat you to the answer, and I am grateful to both of >>>> you, but >>>> sorry I wasted the time of two person, what did I do wrong that you >>>> did not >>>> know that someone already answered? >>> >>> I read emails in the order they come in. I don't always read >>> hundreds >>> or more of messages ahead before I reply to something, that just >>> doesn't >>> scale. >>> >>> Did Xi answer before me? I think our answers just crossed even, a >>> very >>> common thing :-) >> Anyway thanks a lot. >> JH > > Well you could write: > > int dummy; > int result; > asm ("ldrbt\t%0, [%1]" : "=r"(result), "=r"(dummy) : "1"(addr)); > > which describes the behaviour more precisely. The "1" tells the > compiler that addr and dummy must use the same register, but addr will > remain unchanged (so must be copied if it will be used again). > > Or, if you don't mind addr being direclty clobbered, you can write: > > int result; > asm ("ldrbt\t%0, [%1]" : "=r"(result), "+r"(addr)); > > telling the compiler that addr is modified as an inout value. > > R. Hi, Thank you for your answer. Here is my code: #define byte_from_user(addr) ({uint8_t val; __asm__ __volatile__("LDRBT %0, [%1]\n" : "=&r"(val) : "r" (addr), "m"(*addr)); val;}) void dump(const uint8_t * src, size_t count; for(size_t cntsrc=0;cntsrc<count;cntsrc++){ uint8_t data = byte_from_user(&src[cntsrc]); printf("%02X ", data); } printf("\n"); } So the only way to be theoretically correct is to copy addr to a dummy variable and say it will come out of the asm block? Like this: #define byte_from_user(addr) ({uint8_t val; uintptr_t clob_addr = addr; __asm__ __volatile__("LDRBT %0, [%1]\n" : "=&r"(val), "+r"(clob_addr) : "m"(*clob_addr)); val;}) A bit seemingly unnecessarily verbose, but I can live with it if the compiler can deduce it should just produce LDRBT Rx, [Ry] with x!=y and know that Ry is clobbered. (which is actually not the case because it is rewritten with the same value, but this has been described above). Cheers, JH