int main()
{
    unsigned int currentGS = TLS_GET_GS_REG();
    unsigned int currentFS = TLS_GET_FS_REG();

    if ((currentGS == 0) || ((currentGS & 0x4) == 0x4))
    {
        unsigned int ldtEntry = currentGS >> 3;
        unsigned int ldtNextEntry = ldtEntry+1;

        UserDesc tableEntry;
        memset(&tableEntry, 0, sizeof(UserDesc));
        tableEntry.entry_number = ldtNextEntry;
        tableEntry.base_addr = reinterpret_cast<unsigned int>(new unsigned int(0xabcd));
        tableEntry.limit = 0x4000;

        int res = syscall(SYS_modify_ldt, LDT_SET, &tableEntry, sizeof(UserDesc));
        if (res < 0)
        {
            printf("LDT_SET for entry %d failed, code %d, %s\n", ldtNextEntry, errno, strerror(errno) );
            return 0;
        }

        unsigned int newSegVal = (ldtNextEntry << 3) + 7;

        unsigned int GSRes = 0x1;
        unsigned int FSRes = 0x2;
        FarPointer farPtrGS(GSRes, newSegVal);
        FarPointer farPtrFS(FSRes, newSegVal);

        if ((SetGs(&farPtrGS) != GSRes) || (SetFs(&farPtrFS) != FSRes))
        {
            TLS_SET_GS_REG(currentGS);
            TLS_SET_FS_REG(currentFS);
            printf("LFS or LGS failed\n");
            return 0;
        }

        if ((TLS_GET_GS_REG() != newSegVal) || (TLS_GET_FS_REG() != newSegVal))
        {
            TLS_SET_GS_REG(currentGS);
            TLS_SET_FS_REG(currentFS);
            printf("GS or FS wrong value\n");
            return 0;
        }

        if ((GetGsBase() != 0xabcd) || (GetFsBase() != 0xabcd))
        {
            TLS_SET_GS_REG(currentGS);
            TLS_SET_FS_REG(currentFS);
            printf("GS or FS wrong base address\n");
            return 0;
        }
        TLS_SET_GS_REG(currentGS);
        TLS_SET_FS_REG(currentFS);
        printf("LFS and LGS passed successfully\n");
        printf("Base address of GS and FS was synchronuized successfully;\n");

    }
ADDRINT GetTlsBaseAddress()
{
    ADDRINT baseAddress = 0;
#ifdef TARGET_IA32
	unsigned int gsVal = TLS_GET_GS_REG();
	UserDesc td;
	td.entry_number = gsVal >> 3;
    if (gsVal == 0) 
        return 0;
	int  res = syscall(SYS_get_thread_area, &td);
    if (res != 0)
    {
        printf("SYS_get_thread_area failed with error: %s\n", strerror(errno));
        return 0;
    }
    baseAddress = td.base_addr;
#else
    int res = syscall(SYS_arch_prctl, ARCH_GET_FS, &baseAddress);
    if (res != 0)
    {
        printf("SYS_arch_prctl failed with error: %s\n", strerror(errno));
        return 0;
    }
#endif
    return baseAddress;
}
void * thread_func (void *arg)
{
    unsigned long thread_no = (unsigned long)arg+1;

    unsigned int gs_value = TLS_GET_GS_REG();
    sprintf(buf[thread_no-1],"gs value for thread %ld is 0x%x\n", thread_no, gs_value );

	unsigned int gdtEntryMin = GdtFirstEntry();
	unsigned int gdtEntryMax = gdtEntryMin + GDT_NUM_OF_ENTRIES - 1;
	
    for (unsigned int i=gdtEntryMin; i<=gdtEntryMax+1; i++)
    {
        UserDesc thrDescr;
        thrDescr._entry_number = i;
        int res = syscall(SYS_get_thread_area, &thrDescr);
        if (res == 0)
        {
            if (thrDescr._base_addr != mainThreadAddress[i])
                sprintf(buf[thread_no-1],"%s thread %d: base addr for entry %d has been changed by clone()\n", 
                    buf[thread_no-1], thread_no, i);
            else
               sprintf(buf[thread_no-1],"%s thread %d: base addr for entry %d is equal to the same entry in main thread\n", 
                    buf[thread_no-1], thread_no, i); 
        }
        else
        {
           sprintf(buf[thread_no-1],"%s thread %d: SYS_get_thread_area failed for entry %d with error: %s\n", 
           buf[thread_no-1], thread_no, i, strerror(errno));
        }
        
    }

    return 0;
}
int main (int argc, char *argv[])
{
    unsigned long gs_val = TLS_GET_GS_REG();
    while (1)
    {
        loop1 = true;
        loop2 = true;
        pthread_t h[NTHREADS];
        
        pthread_create (&h[0], 0, thread_dlopen_func, 0);
        for (unsigned long i = 1; i < NTHREADS; i++)
        {
            pthread_create (&h[i], 0, thread_func, 0);
        }
        sleep(1);

        loop1 = false;
        loop2 = false;

        for (unsigned long i = 0; i < NTHREADS; i++)
        {
            pthread_join (h[i], 0);
        }
    }    
    return 0;
}