Can you jmp to a memory operand instead of a register value?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
ITchimp
Member
Member
Posts: 134
Joined: Sat Aug 18, 2018 8:44 pm

Can you jmp to a memory operand instead of a register value?

Post by ITchimp »

I finally got my syscall_fork to work...
also I got my scheduler to deviate from james molloy's.. it worked after a few trial and error...

here is my code for doing the actual switch...

Code: Select all

asm volatile( "pushl %%edi;"
                "pushl %%esi;"
                "pushl %%ebx;"
                "movl %%esp, %0;"
                "movl $1f, %1;"
                "movl %%ebp, %2;"
                "movl  %6, %%eax;" // load new cr3
                "movl  %%eax, %%cr3;"
                "movl  %5, %%ebp;"
                "movl  %4, %%esp;" // load new esp
                "jmp  *%3;"
                "1: ;"
                "popl %%ebx;"
                "popl %%esi;"
                "popl %%edi;"
                :"=m"(prev->esp),"=m"(prev->eip), "=m"(prev->ebp)
                :"r"(current_task->eip), "m"(current_task->esp),"g"(current_task->ebp),"m"(current_task->page_dir->phy_addr)      
                :
   );
what I noticed that if I put current_task->eip into a memory operand (ie. "m"(current_task->eip)) it won't work... it will only work if I put it a register...

why is that the case? Can't I jump to a eip located in a memory location?
Last edited by ITchimp on Wed Sep 16, 2020 4:20 pm, edited 1 time in total.
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Can you jmp to a memory operand instead of a register va

Post by Octocontrabass »

Of course you can jump to a memory operand.

The problem is that you've written your inline assembly according to the System V ABI, but the System V ABI only applies to function calls. For inline assembly, all registers are owned by the "caller" and you cannot modify any of them without using them as outputs or putting them in the clobber list. Since you're switching tasks, that means all registers need to be preserved.

I suggest you put your task switch code in an external function instead of using inline assembly.
ITchimp
Member
Member
Posts: 134
Joined: Sat Aug 18, 2018 8:44 pm

Re: Can you jmp to a memory operand instead of a register va

Post by ITchimp »

since eax, edx, and ecx are scratch register, there should not be a need to preserve those.. that was what system V abi says...

are you saying I have to do a pusha and popa to make the code work, and jmp *%3, will them work, be it register or memory?
thewrongchristian
Member
Member
Posts: 426
Joined: Tue Apr 03, 2018 2:44 am

Re: Can you jmp to a memory operand instead of a register va

Post by thewrongchristian »

ITchimp wrote:since eax, edx, and ecx are scratch register, there should not be a need to preserve those.. that was what system V abi says...

are you saying I have to do a pusha and popa to make the code work, and jmp *%3, will them work, be it register or memory?

The part of the ABI you're referring to covers register use across function calls.

You're not calling a function. Therefore, all the registers at the point you're doing the inline assembly, belong to the compiler to use at it sees fit.

If it helps, move away from inline assembly, and do context switching in a self contained assembly, in either a single context switch function (which can trash eax, edx, and ecx) or in a pair of save/restore context functions (which can do the same.)

setjmp/longjmp is an example of the latter, as is getcontext/setcontext (but these are for user context, mentioned here for reference.)

https://wiki.osdev.org/Kernel_Multitasking contains an example of the former.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Can you jmp to a memory operand instead of a register va

Post by Schol-R-LEA »

As an aside, please used [ CODE ] tags in the future, like so:

Code: Select all

asm volatile( "pushl %%edi;"
                "pushl %%esi;"
                "pushl %%ebx;"
                "movl %%esp, %0;"
                "movl $1f, %1;"
                "movl %%ebp, %2;"
                "movl  %6, %%eax;" // load new cr3
                "movl  %%eax, %%cr3;"
                "movl  %5, %%ebp;"
                "movl  %4, %%esp;" // load new esp
                "jmp  *%3;"
                "1: ;"
                "popl %%ebx;"
                "popl %%esi;"
                "popl %%edi;"
                :"=m"(prev->esp),"=m"(prev->eip), "=m"(prev->ebp)
                :"r"(current_task->eip), "m"(current_task->esp),"g"(current_task->ebp),"m"(current_task->page_dir->phy_addr)      
                :
   );
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
linguofreak
Member
Member
Posts: 510
Joined: Wed Mar 09, 2011 3:55 am

Re: Can you jmp to a memory operand instead of a register va

Post by linguofreak »

ITchimp wrote:since eax, edx, and ecx are scratch register, there should not be a need to preserve those.. that was what system V abi says...

are you saying I have to do a pusha and popa to make the code work, and jmp *%3, will them work, be it register or memory?
The ABI talks about what happens when one bit of code gives control to another. It tells each bit of code what it can expect from the other bit of code. The designation of registers as scratch registers means that the code giving control must expect the code receiving control to use those registers.

During a task switch, the task being switched out is, in general, not giving control to the kernel. The kernel is *taking* control without asking. The task may not be ready to transfer control (it may currently be using a scratch register, for instance). Therefore, the kernel needs to save the complete state of the task it's taking control from, and restore that state when it next selects the task to run. If it does not do this, it will almost certainly cause the task to crash.
Post Reply