[gccsdk] Dynamic libraries vs pthreads

Lee Noar leenoar at sky.com
Mon Aug 25 12:53:14 PDT 2008


Peter Naulls wrote:
> Peter Naulls wrote:
>> Lee Noar wrote:
> 
>>> Does it fail in pthread_yield_return by any chance?
>>
>> Well, I certainly don't have enough information to rule out
>> the later crash there.  Anyway, thanks for looking as this;
>> people are not often interested in looking at such hard
>> problems :-|
>>
> 
> Incidentally, I put a pthread_yield in a simple X program
> using shared libraries, and it worked fine.

Perhaps it's a StrongARM thing. The reason I ask is that the following 
code failed to work when built dynamically, but worked perfectly when 
built statically:

--8<-- pthread-test-lib1.c --

#include <stdio.h>
#include <pthread.h>

static int x = 10;

static pthread_t lib_thread;

static void *
tf (void *arg)
{
   while (1)
   {
     printf("Library 1 thread before yield: %d\n", x);
     pthread_yield();
     printf("Library 1 thread after yield: %d\n", x);
   }
}

void pthread_lib1_create(void)
{
   if (pthread_create(&lib_thread, NULL, tf, NULL) != 0)
     printf("Failed to create thread in library 1\n");
}

--8<--

--8<-- pthread-test-lib2.c --

#include <stdio.h>
#include <pthread.h>

static int x = 20;

static pthread_t lib_thread;

static void *
tf (void *arg)
{
   while (1)
   {
     printf("Library 2 thread before yield: %d\n", x);
     pthread_yield();
     printf("Library 2 thread after yield: %d\n", x);
   }
}

void pthread_lib2_create(void)
{
   if (pthread_create(&lib_thread, NULL, tf, NULL) != 0)
     printf("Failed to create thread in library 2\n");
}

--8<--

--8<-- pthread-test-main.c --

#include <stdio.h>

extern void pthread_lib1_create(void);
extern void pthread_lib2_create(void);

static int x = 30;

int main(void)
{
   pthread_lib1_create();
   pthread_lib2_create();

   while (1)
   {
     printf("In main before yield: %d\n", x);
     pthread_yield();
     printf("In main after yield: %d\n", x);
   }

   return 0;
}

--8<--

Dynamic build:

arm-unknown-riscos-gcc pthread-test-lib1.c -O2 -o libpthread-test1.so 
-shared -fPIC

arm-unknown-riscos-gcc pthread-test-lib2.c -O2 -o libpthread-test2.so 
-shared -fPIC

arm-unknown-riscos-gcc pthread-test-main.c -O2 -o pthread-test-main,e1f 
-L. -lpthread-test1 -lpthread-test2

Static build:

arm-unknown-riscos-gcc pthread-test-main.c pthread-test-lib1.c 
pthread-test-lib2.c -O2 -o pthread-test-main-S,e1f -static

There are 3 threads including the main one. In the dynamic build, each 
thread is called once upto pthread_yield, but when switching from the 
last back to the first it crashes.
Initially, I traced it to pthread_yield_return which conists of one 
instruction that restores registers from the stack based on fp. Although 
fp pointed into the stack, it was not to a stack frame.
Eventually, I traced this to the STMFD instruction in pthread_yield:

   STMDB	a1, {r4-r14}^

I found that for the first thread, it failed to save r14 into __cbreg so 
all registers saved were one register out of step and on the reload, 
instead of restoring fp(r11) to fp(r11), it restored sl(r10) to fp(r11) 
hence the pointer into the stack. I confirmed that the base register was 
correct and not 4 bytes out and the other two threads were correctly 
saved. I've search ARM's documents for the StrongARM looking for a CPU 
bug, but I can't find anything and that wouldn't explain why the static 
build works.

I've found that using this sequence instead stops the crash:

  ADD	a1, a1, #13*4
  STMDB	a1, {r4-r12}
  STMIA	a1!,{r13,r14}^

Can anyone reproduce these results?

Thanks,
Lee.





More information about the gcc mailing list