Mail Archives: djgpp/2000/03/26/12:46:29
David Cleaver wrote:
>> extern __inline__ void _farpokex (unsigned short selector,
>> unsigned long offset,
>> void *x, int len)
>> {
>> __asm__ __volatile__ ("pushl %%es\n"
>> "movw %w3, %%es\n"
>> "rep\n"
>> "movsb\n"
>> "popl %%es"
>> : "=S" (x), "=D" (offset), "=c" (len)
>> : "r" (selector), "0" (x), "1" (offset), "2" (len));
>> }
>>
>> But I wonder, whether it is allowed, to change es without
>> wrapping it into cli/sti pairs. (An ISR may assume stanard es)
>Thank you for posting your response. But, because I don't understand
>'asm', I would like to ask several questions regarding your post:
I suggest, reading the FAQ, question 18.12. The gcc manual will
explain, how to do inline assembly with gcc. BTW. If you don't
understand inline assembly (yet), you may want to have a look
at the movedata function, that can do exactly the same as your _farpokex.
And even when you understand inline assembly, movedata can be preferable in
many situations, but it won't get inlined. However, it will be
more efficient for large data move.
>1. Why did you change "rm" (selector) to "r" (selector)?
I do not know, whether "rm" is allowed, but I do know, that "r" is
allowed, and that it should work. "r" means, put it in any general
purpose register.
>2. Do the variables have to be put into some specific order? (like it
> seems you have done above.)
Not in general, but input and output lists must be consistent,
see below. Also, after reordering the lists you must renumber
the 3 in "movw %w3, %%es\n", when selector is not the fourth
register anymore. You probably noticed, that it was "movw %w0, %%es\n"
in the original code.
>3. Why wasn't an equal-sign put in front of the "rm" variable?
It is input only, and it won't be changed (clobbered) by the code.
>4. Why did you choose zero for x, and one for offset, and two for len,
> and nothing for selector?
X is int the first register in the output list. You refer to the first
output register by "0", to the second by "1", etc. in the input list.
So for x, you are saying to the compiler, overwrite x with whatever is
ESI after the assembly. Also you tell the compiler that x should be in
ESI (which is "0" here, AFAIK using "S" instead of "0", does not
work), before your assembler code starts.
This is the "new" (and non obvious) method, to tell the compiler,
that the input register ESI was changed by the assembler code.
Earlier you could put "ESI" in the clobber list, and did not
need the output list at all for this. (This is how your original
code worked.)
Please note, that the method I described, works here only, because
you don't need x anymore. If you would need x later, you would
need a temporary variable.
So instead of
: "=S" (x), "=D" (offset), "=c" (len)
: "r" (selector), "0" (x), "1" (offset), "2" (len));
you could write
{
unsigned temp1, temp2, temp3;
/* __asm__( ...
: "=S" (temp1), "=D" (temp2), "=c" (temp3)
: "r" (selector), "0" (x), "1" (offset), "2" (len));
}
/* can use unchanged x here */
>5. I really don't know anything about cli/sti pairs (or an ISR)!
> What do these terms mean?
Cli: clear interrupt flag, sti: set interrupt flag. Code between
cli and sti will not be interrupted (by maskable external interrupts).
ISR: interrupt service routine.
But, as I said, I have no idea whether one has to take care of the
modified ES.
So, my question to the experts is:
When you temporarily change ES, and an assyncron signal will
be raised, will the signal handler see the changed ES or the
standard ES=DS? (Off topic, but would this be differnt under
linux?)
- Raw text -