Hi,
OK, I used AS and NDISASM, and NASM and OBJDUMP to work out exactly what AT&T syntax means what. The following should be 100% correct.
pcmattman wrote:A far jump syntax is (not back-to-front like everything else in AT&T syntax)
That is an "immediate far jump", not an "indirect far jump".
For an "immediate far jump" (where the target is hardcoded in the instruction) you'd want (NASM):
Or (AT&T):
For an "indirect far jump" (where the target is stored in memory somewhere), you'd want (NASM):
Code: Select all
jmp far [address_of_offset]
jmp far [eax]
Or (AT&T):
Code: Select all
ljmp *address_of_offset
ljmp *(%eax)
For an "indirect far jump" (where the target is stored in memory somewhere, but you've got the address of the selector instead of the address of the offset (for 32-bit code), you'd want (NASM):
Code: Select all
jmp far [address_of_selector - 4]
jmp far [eax - 4]
Or (AT&T):
Code: Select all
ljmp *address_of_selector-4
ljmp *-4(%eax)
Combining all of this, when you want an indirect far jump in AT&T inline assembly where the characters "%0" are replaced by the (32-bit) address of where the selector is stored (and not the 32-bit address of where the offset is stored), you'd want:
Code: Select all
__asm__ __volatile__ ("ljmp *-4%0\n" : :"m"(selector));
Unfortunately this doesn't work. GCC replaces the "%0" with "8(%ebp)" so you end up with:
It seems GAS/GCC is too stupid to add 2 numbers together and come up with the correct code:
To fix this you need to get the compiler to calculate the address you want, rather than using GAS:
Code: Select all
void far_jmp(unsigned int volatile selector) {
__asm__ __volatile__ ("ljmp *%0\n" : :"r"((void *)&selector - 4));
}
The final result (compiled with "-S" and no optimisation) is:
Code: Select all
.globl far_jmp
.type far_jmp, @function
far_jmp:
pushl %ebp
movl %esp, %ebp
leal 4(%ebp), %eax
#APP
ljmp *%eax
#NO_APP
popl %ebp
ret
.size far_jmp, .-far_jmp
Compiled with "-S -fomit-frame-pointer -O3" you get:
Code: Select all
.globl far_jmp
.type far_jmp, @function
far_jmp:
#APP
ljmp *%esp
#NO_APP
ret
NOTE: If you don't define the function as "void far_jmp(unsigned int volatile selector)" and use "void far_jmp(unsigned int selector)" instead, then GCC's optimiser decides the value passed in "selector" doesn't get used and doesn't bother passing it - instead it does a far jump to an address stored in uninitialised data on the stack(!)...
[EDIT]
Hehe - found the problem. Use this instead:
Code: Select all
void far_jmp(unsigned int selector) {
__asm__ __volatile__ ("ljmp *%0\n" : :"r"((void *)&selector - 4) : "memory");
}
It seems the clobberlist is useful for more than just clobbered things...
![Wink ;)](./images/smilies/icon_wink.gif)
[/EDIT]
Cheers,
Brendan