x86 assembly help request
Joel Sherrill
joel.sherrill at oarcorp.com
Wed May 30 13:30:10 UTC 2007
Till Straumann wrote:
> I downloaded a recent glibc (cvs head actually) and could reproduce
> your problem. However, this new version mangles the stack pointer
> and destination address yet differently than what you posted
> (bit rot in addition to xor).
>
> Therefore, I believe it is not a good idea to try to edit glibc's
> jmp_buf in any way.
>
> Rather, I'd switch temporarily to the target context's stack
> and call setjmp from there. A quick (and dirty) hack worked
> for me (attached).
>
On FC5, with gcc (GCC) 4.1.1 20070105 (Red Hat 4.1.1-51)
/home/joel/rtems-4.8-work/rtems/c/src/../../cpukit/score/cpu/unix/cpu.c:463:
internal compiler error: in splice_child_die, at dwarf2out.c:5503
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://bugzilla.redhat.com/bugzilla> for instructions.
Preprocessed source stored into /tmp/ccSMDqGp.out file, please attach
this to your bugreport.
> Disclaimer: this is not necessarily the best (most elegant + portable)
> solution but the last I can squeeze out of my brain after a 21h day...
>
I was considering using the newlib setjmp.s and including it as cpu_asm.S
on the linux port. :)
Maybe this is the easiest thing to do.
--joel
> -- T.
>
> Joel Sherrill wrote:
>> Hi,
>>
>> I have been trying to get the unix BSP to run
>> on Fedora Core 6. AFAIK it hasn't run in a long
>> time. In doing so, I have noticed that
>> we no longer do the correct magic to fill
>> in the setjmp structure correctly. The
>> setjmp fields are at the following indices
>> if you view it as a uint32_t array:
>>
>> #define EBX_OFF 0
>> #define ESI_OFF 1
>> #define EDI_OFF 2
>> #define EBP_OFF 3
>> #define ESP_OFF 4
>> #define RET_OFF 5
>>
>> We appear to be putting in the values correctly
>> at the correct offsets EXCEPT that setjmp and
>> longjmp are doing something with the stack pointers:
>>
>>
>> (gdb) disassemble setjmp
>> Dump of assembler code for function setjmp:
>> 0x00482ac0 <setjmp+0>: mov 0x4(%esp),%eax
>> 0x00482ac4 <setjmp+4>: mov %ebx,(%eax)
>> 0x00482ac6 <setjmp+6>: mov %esi,0x4(%eax)
>> 0x00482ac9 <setjmp+9>: mov %edi,0x8(%eax)
>> 0x00482acc <setjmp+12>: lea 0x4(%esp),%ecx
>> 0x00482ad0 <setjmp+16>: xor %gs:0x18,%ecx <======
>> 0x00482ad7 <setjmp+23>: mov %ecx,0x10(%eax)
>> 0x00482ada <setjmp+26>: mov (%esp),%ecx
>> 0x00482add <setjmp+29>: xor %gs:0x18,%ecx
>> 0x00482ae4 <setjmp+36>: mov %ecx,0x14(%eax) <========
>> 0x00482ae7 <setjmp+39>: mov %ebp,0xc(%eax)
>> 0x00482aea <setjmp+42>: push $0x1
>> 0x00482aec <setjmp+44>: pushl 0x8(%esp)
>> 0x00482af0 <setjmp+48>: call 0x482a60 <__sigjmp_save>
>> 0x00482af5 <setjmp+53>: pop %ecx
>> 0x00482af6 <setjmp+54>: pop %edx
>> 0x00482af7 <setjmp+55>: ret
>> 0x00482af8 <setjmp+56>: nop
>>
>> Similarly for longjmp:
>>
>> gdb) disassemble
>> Dump of assembler code for function __longjmp:
>> 0x00482ba0 <__longjmp+0>: mov 0x4(%esp),%eax
>> 0x00482ba4 <__longjmp+4>: mov 0x14(%eax),%edx
>> 0x00482ba7 <__longjmp+7>: mov 0x10(%eax),%ecx
>> 0x00482baa <__longjmp+10>: xor %gs:0x18,%edx <=======
>> 0x00482bb1 <__longjmp+17>: xor %gs:0x18,%ecx <=======
>> 0x00482bb8 <__longjmp+24>: mov (%eax),%ebx
>> 0x00482bba <__longjmp+26>: mov 0x4(%eax),%esi
>> 0x00482bbd <__longjmp+29>: mov 0x8(%eax),%edi
>> 0x00482bc0 <__longjmp+32>: mov 0xc(%eax),%ebp
>> 0x00482bc3 <__longjmp+35>: mov 0x8(%esp),%eax
>> 0x00482bc7 <__longjmp+39>: mov %ecx,%esp
>> 0x00482bc9 <__longjmp+41>: jmp *%edx
>> 0x00482bcb <__longjmp+43>: nop
>>
>> The newlib linux/x86 setjmp is the same one we use on
>> RTEMS which does NOT do the xor magic. So it isn't
>> much help. We get a SEGV when we load the %ESP since
>> it apparently isn't being adjusted correctly or is
>> not a valid address for a stack pointer.
>>
>> This is done by a macro PTR_MANGLE in the glibc source.
>> I believe I have duplicated this mangling and now may
>> be getting hit by bounds checks on the stack pointer.
>> We are really one thread to Linux and we are changing
>> the stack underneath it. That would explain a SEGV.
>>
>> Any ideas, thoughts, patches. :)
>>
>> --joel
>> _______________________________________________
>> rtems-users mailing list
>> rtems-users at rtems.com
>> http://rtems.rtems.org/mailman/listinfo/rtems-users
>>
>
> ------------------------------------------------------------------------
>
> Index: cpu.c
> ===================================================================
> RCS file: /usr1/CVS/rtems/cpukit/score/cpu/unix/cpu.c,v
> retrieving revision 1.48
> diff -c -r1.48 cpu.c
> *** cpu.c 30 Mar 2004 11:48:30 -0000 1.48
> --- cpu.c 30 May 2007 07:53:46 -0000
> ***************
> *** 453,458 ****
> --- 453,527 ----
>
> }
>
> +
> + typedef struct AuxFrame_ {
> + /* stack builds down from here */
> + uint32_t ebx, esi, edi;
> + void (*eip)();
> + jmp_buf *pjb;
> + uint32_t old_esp;
> + } AuxFrame __attribute__((may_alias));
> +
> + /* MUST make sure this is called in a new frame so it
> + * uses the new stack
> + */
> + static void trampo(void (*pc)(), jmp_buf *pjb)
> + __attribute__((noinline));
> +
> + static void trampo(void (*pc)(), jmp_buf *pjb)
> + {
> + if ( setjmp( *pjb ) )
> + pc();
> + }
> +
> + /* Same as above; this should probably be entirely coded in assembly
> + * to avoid problems
> + */
> + static void cpy_jmpbuf(AuxFrame *new_sp) __attribute__((noinline));
> +
> + /*
> + * NOTE: this routine relies on the layout of 'AuxFrame' above
> + *
> + * INPUT: pointer to a AuxFrame on new stack;
> + *
> + * What it does:
> + * 1) save current SP in new stack frame
> + * 2) switch stack to new_sp
> + * 3) load registers with desired values (except for PC)
> + * 4) call setjmp() to store context
> + * 4a) setjmp returns 0: restore SP and leave
> + * 4b) setjmp returns 1 (got here from longjmp):
> + * call code at PC
> + */
> + static void cpy_jmpbuf(AuxFrame *new_sp)
> + {
> + asm volatile(
> + /* Save current ESP in AuxFrame */
> + " movl %%esp,0x14(%0) \n"
> + /* Switch ESP to new stack (AuxFrame) */
> + " movl %0, %%esp \n"
> + /* Pop off / load EBX */
> + " popl %%ebx \n"
> + /* Pop off / load ESI */
> + " popl %%esi \n"
> + /* Pop off / load EDI */
> + " popl %%edi \n"
> + /* Pop off EBP; this should never be
> + * used - 'trampo' is a C routine and
> + * saves-restores the 'deadcafe' value.
> + */
> + " movl $0xdeadcafe,%%ebp\n"
> + /* Call trampoline */
> + " call trampo \n"
> + /* If we return (setjmp returned 0)
> + * then we restore the old SP
> + */
> + " movl 8(%%esp),%%esp \n"
> + ::"r"(new_sp):"ebx","esi","edi");
> +
> + /* When leaving this routine, the original EBP is restored */
> + }
> +
> /*PAGE
> *
> * _CPU_Context_Initialize
> ***************
> *** 539,562 ****
> * This information was gathered by disassembling setjmp().
> */
>
> ! {
> ! uint32_t stack_ptr;
>
> ! stack_ptr = _stack_high - CPU_FRAME_SIZE;
>
> ! *(addr + EBX_OFF) = 0xFEEDFEED;
> ! *(addr + ESI_OFF) = 0xDEADDEAD;
> ! *(addr + EDI_OFF) = 0xDEAFDEAF;
> ! *(addr + EBP_OFF) = stack_ptr;
> ! *(addr + ESP_OFF) = stack_ptr;
> ! *(addr + RET_OFF) = jmp_addr;
> !
> ! addr = (uint32_t *) stack_ptr;
> !
> ! addr[ 0 ] = jmp_addr;
> ! addr[ 1 ] = (uint32_t ) stack_ptr;
> ! addr[ 2 ] = (uint32_t ) stack_ptr;
> ! }
>
> #else
> #error "UNKNOWN CPU!!!"
> --- 608,626 ----
> * This information was gathered by disassembling setjmp().
> */
>
> ! {
> ! AuxFrame *stack_ptr;
>
> ! stack_ptr = (AuxFrame*)( _stack_high - sizeof(AuxFrame));
> ! stack_ptr->ebx = 0xFEEDFEED;
> ! stack_ptr->esi = 0xDEADDEAD;
> ! stack_ptr->edi = 0xDEAFDEAF;
> ! stack_ptr->eip = (void (*)())jmp_addr;
> ! stack_ptr->pjb = &((Context_Control_overlay *)_the_context)->regs;
>
> ! cpy_jmpbuf(stack_ptr);
> !
> ! }
>
> #else
> #error "UNKNOWN CPU!!!"
>
More information about the users
mailing list