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