1

I've just read about support for %fs and %gs segment prefixes on the Intel platforms in GCC. It was mentioned that "The way you obtain %gs-based pointers, or control the value of %gs itself, is out of the scope of gcc;"

I'm looking for a way when I manually can set the value of %fs (I'm on IA32, RH Linux) and work with it. When I just set %fs=%ds the test below works fine and this is expected. But I cannot change the test in order to have another value of %fs and do not get a segmentation fault. I start thinking that changing the value of %fs is not the only thing to do. So I'm looking for an advice how to make a part of memory addressed by %fs that is not equal to DS.

#include <stddef.h>

typedef char __seg_fs fs_ptr;
fs_ptr p[] = {'h','e','l','l','o','\0'};

void fs_puts(fs_ptr *s)
{
    char buf[100];

    buf[0] = s[0];
    buf[1] = s[1];
    buf[2] = s[2];
    buf[3] = '\0';

    puts(buf);
}

void __attribute__((constructor)) set_fs()
{
    __asm__("mov %ds, %bx\n\t"
            "add $0, %bx\n\t"      //<---- if fs=ds  then the program executes as expected. If not $0 here, then segmentation fault happens.        
            "mov %bx, %fs\n\t");
}

int main()
{
    fs_puts(p);

    return 0;
}         
Andrei
  • 107
  • 1
  • 1
  • 5

1 Answers1

2

I've talked with Armin who implemented __seg_gs/__seg_fs in GCC (Thanks Armin!). So basically I cannot use these keywords for globals. The aim of introducing __seg_gs/fs was to have a possibility to dynamically allocate regions of memory that are thread-local. We cannot use __thread for a pointer and to allocate a memory for it using malloc. But __seg_gs/fs introduce such possibility. The test below somehow illustrates that. Note that arch_prctl() was used. It exists as 64-bit version only. Also note that %fs is used for __thread on 64-bit and %gs is free.

#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <asm/ldt.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <asm/prctl.h>
#include <sys/syscall.h> 
#include <unistd.h> 

typedef __seg_gs char gs_str;

void gs_puts(gs_str *ptr)
{
    int i;
    char buf[100];
    for(i = 0; i < 100; i++)
        buf[i] = ptr[i];

    puts(buf);
}

int main()
{
    int i;
    void *buffer = malloc(100 * sizeof(char));

    arch_prctl(ARCH_SET_GS, buffer);

    gs_str *gsobj = (gs_str *)0;
    for (i = 0; i < 100; i++)
        gsobj[i] = 'a';       /* in the %gs space */

    gs_puts(gsobj);

    return 0;
}
Andrei
  • 107
  • 1
  • 1
  • 5