The problem with using GCC's inline asm to learn assembly is that you spend half your time learning about how gcc's inline assembly works instead of actually learning assembly. For example here's how I might write this same code:
#include <stdio.h>
int getStringLength(const char *pStr){
int len;
__asm__ (
"repne scasb
"
"not %%ecx
"
"dec %%ecx"
:"=c" (len), "+D"(pStr) /*Outputs*/
:"c"(-1), "a"(0) /*Inputs*/
/* tell the compiler we read the memory pointed to by pStr,
with a dummy input so we don't need a "memory" clobber */
, "m" (*(const struct {char a; char x[];} *) pStr)
);
return len;
}
See the compiler's asm output on the Godbolt compiler explorer. The dummy memory-input is the tricky part: see discussion in comments and on the gcc mailing list for the most optimal way to do this which is still safe.
Comparing this with your example
- I don't initialize
len
, since the asm declares it as an output (=c).
- There's no need to copy
pStr
since it is a local variable. By spec, we're already allowed to change it (although since it is const
we shouldn't modified the data it points to).
- There's no reason to tell the inline asm to put
Ptr
in eax
, only to have your asm move it to edi
. I just put the value in edi
in the first place. Note that since the value in edi
is changing, we can't just declare it as an 'input' (by spec, inline asm must not change the value of inputs). Changing it to a read/write output solves this problem.
- There's no need to have the asm zero
eax
, since you can have the constraints do it for you. As a side benefit, gcc will 'know' that it has 0 in the eax
register, and (in optimized builds) it can re-use it (think: checking the length of 2 strings).
- I can use the constraints to initialize
ecx
too. As mentioned, changing the value of inputs is not allowed. But since I define ecx
as an output, gcc already knows that I'm changing it.
- Since the contents of ecx, eax and edi are all explicitly specified, there's no need to clobber anything anymore.
All of which makes for (slightly) shorter and more efficient code.
But this is ridiculous. How the heck (can I say 'heck' on SO?) are you supposed to know all that?
If the goal is to learn asm, using inline asm is not your best approach (in fact I'd say that inline asm is a bad idea in most cases). I'd recommend that you declare getStringLength as an extern and write it completely in asm then link it with your C code.
That way you learn about parameter passing, return values, preserving registers (along with learning which registers must be preserved and which you can safely use as scratch), stack frames, how to link asm with C, etc, etc, etc. All of which is more useful to know than this gobbledygook for inline asm.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…