Mail Archives: djgpp/2002/02/08/14:09:16
Well, OK, so I'll bite it...
Joel Saunders <jbs30000 AT aol DOT com> wrote:
> Ok, I have the variables:
> char *Screen_PTR = (char *)(0xB8000 + __djgpp_conventional_base);
> char My_Name[9] = {"J O E L "};
> I have the macro
> #define Mov_Byte(Src, Dest, Mov_Size)\
Hmm... it might be better to make that an inlined function ("extern
inline" in the header file). Otherwise, you might end up in trouble
if someone passes somewhat more complicated arguments.
Of course, this particular example is completely moot --- just calling
memcpy() would produce the exact same result already. GCC has a
builtin inlined version of that standard function.
> __asm__ __volatile__(\
> "cld\n\t"\
> "rep\n\t"\
> "movsb"\
> : :"S" (Src), "D" (Dest), "c" (Mov_Size))
If this were fully correct, you wouldn't need any __volatile__
qualifier. That's usually only needed for insufficiently instrumented
extended asm blocks.
What you're saying is that you want Src in %esi, and Dest in %edi, and
Mov_Size into %ecx. Fine.
> This works:
> Mov_Byte(&My_Name[0], &Screen_PTR[0], 8);
^^^^^^^^^^^
It shouldn't ever be necessary to write it this way. Simply
Mov_Byte(My_Name, Screen_PTR, 8);
should suffice. Esp. if you used an inline function, so the compiler
gets a chance to know the types of the arguments to be passed to this
function, too.
> However, if I rewrite the macro like this:
Question: why do you want to rewrite it like this? Didn't the other
version work already?
> #define Mov_Byte(Src, Dest, Mov_Size)\
> __asm__ __volatile__(\
> "cld\n\t"\
> "rep\n\t"\
> "movsb"\
> : :"S" (Src), "D" (Dest), "c" (Mov_Size)\
> :"%ecx", "%esi", "%edi"
That's wrong, indeed. You're not supposed to have the same registers
in both the input/output and the clobber lists. The clobber list is
for other registers modified by the code, but which are not in the
input/output lists. There was a change in this area between GCC-2.8.1
and 2.95.something. The error message has changed, but the solution
from the DJGPP FAQ (8.17) should still apply. Unfortunately, that
particular GCC FAQ section it points no longer seems to be there.
In a nutshell: set up dummy variables (one per 'clobbered' register),
and set them up as output locacions for those registers. As you're
going to mention some registers twice, this gets a bit more tricky:
you have to reference an earlier constraint by running index.
Furthermore, I don't think you have to mark esi and edi as clobbered,
for this: their values aren't actually modified by the code. Only ecx
is.
> Error: Can't find a register in class `CREG' while reloading `asm'.
The error message seems to have changed in recent GCC's, but I still
assume it's that same old problem. IIRC, it used to say "fixed or
forbidden register was spilled".
All that said, I think a correct version would look like this:
extern inline void Mov_Byte(void *Src, void *Dest, size_t Mov_Size)
{
unsigned int dummy;
__asm__ (
"cld\n\t"
"rep\n\t"
"movsb"
:"=c" (dummy)
:"S" (Src), "D" (Dest), "0" (Mov_Size)
:"memory"
);
}
But note that this is 100% untested.
--
Hans-Bernhard Broeker (broeker AT physik DOT rwth-aachen DOT de)
Even if all the snow were burnt, ashes would remain.
- Raw text -