https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70220
--- Comment #9 from Wink Saville <wink at saville dot com> ---
(In reply to H.J. Lu from comment #8)
> (In reply to Wink Saville from comment #7)
> >
> > In my opinion, even if rbp is special, it still needs to be available in the
> > struct full_stack_frame.
>
> The whole idea of extending interrupter attribute is to avoid
> full_stack_frame.
> ISR shouldn't assume that compiler will save and restore registers in any
> specific way, order or form. As far as ISR is concerned, it is just black
> magic.
>From my perspective the goal is not to avoid struct full_stack_frame but to
allow it to be created and always consistent.
>
> > Also, isn't rsp special? Would the compiler or programmer be responsible for
> > initializing it. It seems to me it has to be the compiler, but could be
> > wrong.
>
> If you change rsp in asm statement, you have to restore it in asm statement.
The rsp is always saved/restored by the hardware, and your struct frame pointer
provides access to it so no problem there. It is special because when there are
local variables the compiler needs to modify it and currently it does that
after the registers are saved. How will we coordinate the compiler initializing
rsp and the programming saving the registers?
One possibility I see is that the programmer adds struct saved_regs as a local
variable (or TLS or ...) and then saves and restores the registers to/from
there. So assuming rbp is special and always points to itself then maybe
something like:
struct saved_regs {
ac_u64 rax;
ac_u64 rdx;
ac_u64 rcx;
ac_u64 rbx;
ac_u64 rsi;
ac_u64 rdi;
ac_u64 r8;
ac_u64 r9;
ac_u64 r10;
ac_u64 r11;
ac_u64 r12;
ac_u64 r13;
ac_u64 r14;
ac_u64 r15;
ac_u64 rbp;
};
__attribute__((__interrupt__(all)))
void test_isr(struct intr_frame* frame) {
struct saved_regs sr;
__asm__ volatile("mov %%rax, %0;" : "=m"(sr.rax));
...
__asm__ volatile("mov %%r15, %0;" : "=m"(sr.r15));
__asm__ volatile("mov (%rbp), %rax;");
__asm__ volatile("mov %%rax, %0;" : "=m"(sr.rbp));
ac_printf("timer_reschedule_isr sr.rax=%x\n", sr.rax);
tcb_x86 *ptcb = thread_scheduler((ac_u8*)get_sp(), get_ss());
__asm__ volatile("movq %0, %%rsp;" :: "rm" (ptcb->sp) : "rsp");
__asm__ volatile("movw %0, %%ss;" :: "rm" (ptcb->ss));
set_apic_timer_initial_count(ptcb->slice);
__atomic_add_fetch(&timer_reschedule_isr_counter, 1, __ATOMIC_RELEASE);
send_apic_eoi();
__asm__ volatile("mov %0, %%rax;" :: "m"(sr.rbp));
__asm__ volatile("mov %rax, (%rbp);");
__asm__ volatile("mov %0, %%r15;" :: "m"(sr.r15));
...
__asm__ volatile("mov %0, %%rax;" :: "m"(sr.rax));
}
The current compiler generates:
0000000000100490 <test_isr>:
100490: 55 push %rbp
100491: 48 89 e5 mov %rsp,%rbp
100494: 41 53 push %r11
100496: 41 52 push %r10
100498: 41 51 push %r9
10049a: 41 50 push %r8
10049c: 57 push %rdi
10049d: 56 push %rsi
10049e: 51 push %rcx
10049f: 52 push %rdx
1004a0: 50 push %rax
1004a1: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
1004a5: 48 83 c4 80 add $0xffffffffffffff80,%rsp
1004a9: fc cld
1004aa: 48 89 44 24 08 mov %rax,0x8(%rsp)
1004af: 4c 89 7c 24 78 mov %r15,0x78(%rsp)
1004b4: 48 8b 45 00 mov 0x0(%rbp),%rax
1004b8: 48 89 44 24 38 mov %rax,0x38(%rsp)
...
10050d: 48 8b 44 24 38 mov 0x38(%rsp),%rax
100512: 4c 8b 7c 24 78 mov 0x78(%rsp),%r15
100517: 48 89 45 00 mov %rax,0x0(%rbp)
10051b: 48 8b 44 24 08 mov 0x8(%rsp),%rax
100520: 48 8d 65 b8 lea -0x48(%rbp),%rsp
100524: 58 pop %rax
100525: 5a pop %rdx
100526: 59 pop %rcx
100527: 5e pop %rsi
100528: 5f pop %rdi
100529: 41 58 pop %r8
10052b: 41 59 pop %r9
10052d: 41 5a pop %r10
10052f: 41 5b pop %r11
100531: 5d pop %rbp
100532: 48 cf iretq
Obviously the "new" compiler wouldn't be saving/restoring r11..rax, that would
be the programmers responsibility, but it looks like it works.