blob: 119a5debd6f04869496bd2e57457685d196eabe8 [file]
/* Copyright (C) 2010 LunarG Inc.
* SPDX-License-Identifier: MIT
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#include "glapi/glapi.h"
struct mapi_stub {
size_t name_offset;
int slot;
};
/* Implemented in mesa/main/context.c. */
void
_mesa_noop_entrypoint(const char *name);
#define MAPI_TMP_NOOP_ARRAY
#define MAPI_TMP_PUBLIC_STUBS
#include "shared_glapi_mapi_tmp.h"
/* REALLY_INITIAL_EXEC implies __GLIBC__ */
#if defined(USE_X86_ASM) && defined(REALLY_INITIAL_EXEC)
#include "entry_x86_tls.h"
#define MAPI_TMP_STUB_ASM_GCC
#include "shared_glapi_mapi_tmp.h"
#ifndef GLX_X86_READONLY_TEXT
__asm__(".balign 16\n"
"x86_entry_end:");
__asm__(".text");
#endif /* GLX_X86_READONLY_TEXT */
extern unsigned long
x86_current_tls();
extern char x86_entry_start[] HIDDEN;
extern char x86_entry_end[] HIDDEN;
static inline _glapi_proc
entry_generate_or_patch(int, char *, size_t);
static void
entry_patch_public(void)
{
#ifndef GLX_X86_READONLY_TEXT
char *entry;
int slot = 0;
for (entry = x86_entry_start; entry < x86_entry_end;
entry += X86_ENTRY_SIZE, ++slot)
entry_generate_or_patch(slot, entry, X86_ENTRY_SIZE);
#endif
}
static _glapi_proc
entry_get_public(int slot)
{
return (_glapi_proc) (x86_entry_start + slot * X86_ENTRY_SIZE);
}
static void
entry_patch(_glapi_proc entry, int slot)
{
char *code = (char *) entry;
*((unsigned long *) (code + 8)) = slot * sizeof(_glapi_proc);
}
static inline _glapi_proc
entry_generate_or_patch(int slot, char *code, size_t size)
{
const char code_templ[16] = {
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, /* movl %gs:0x0, %eax */
0xff, 0xa0, 0x34, 0x12, 0x00, 0x00, /* jmp *0x1234(%eax) */
0x90, 0x90, 0x90, 0x90 /* nop's */
};
_glapi_proc entry;
if (size < sizeof(code_templ))
return NULL;
memcpy(code, code_templ, sizeof(code_templ));
*((unsigned long *) (code + 2)) = x86_current_tls();
entry = (_glapi_proc) code;
entry_patch(entry, slot);
return entry;
}
#elif defined(USE_X86_64_ASM) && defined(REALLY_INITIAL_EXEC)
#include "entry_x86-64_tls.h"
#define MAPI_TMP_STUB_ASM_GCC
#include "shared_glapi_mapi_tmp.h"
#include <string.h>
static void
entry_patch_public(void)
{
}
extern char
x86_64_entry_start[] HIDDEN;
static _glapi_proc
entry_get_public(int slot)
{
return (_glapi_proc) (x86_64_entry_start + slot * 32);
}
#elif defined(USE_PPC64LE_ASM) && UTIL_ARCH_LITTLE_ENDIAN && defined(REALLY_INITIAL_EXEC)
#include "entry_ppc64le_tls.h"
#define MAPI_TMP_STUB_ASM_GCC
#include "shared_glapi_mapi_tmp.h"
#include <string.h>
static void
entry_patch_public(void)
{
}
extern char
ppc64le_entry_start[] HIDDEN;
static _glapi_proc
entry_get_public(int slot)
{
return (_glapi_proc) (ppc64le_entry_start + slot * PPC64LE_ENTRY_SIZE);
}
#else
/* C version of the public entries */
#define MAPI_TMP_DEFINES
#define MAPI_TMP_PUBLIC_ENTRIES
#include "shared_glapi_mapi_tmp.h"
static void
entry_patch_public(void)
{
}
static _glapi_proc
entry_get_public(int slot)
{
return public_entries[slot];
}
#endif /* asm */
/* Current dispatch and current context variables */
__THREAD_INITIAL_EXEC struct _glapi_table *_mesa_glapi_tls_Dispatch
= (struct _glapi_table *)table_noop_array;
__THREAD_INITIAL_EXEC void *_mesa_glapi_tls_Context;
static int
stub_compare(const void *key, const void *elem)
{
const char *name = (const char *)key;
const struct mapi_stub *stub = (const struct mapi_stub *)elem;
return strcmp(name, &public_string_pool[stub->name_offset]);
}
/**
* Return size of dispatch table struct as number of functions (or
* slots).
*/
unsigned
_mesa_glapi_get_dispatch_table_size(void)
{
return _gloffset_COUNT;
}
static const struct mapi_stub *
_glapi_get_stub(const char *name)
{
if (!name || name[0] != 'g' || name[1] != 'l')
return NULL;
return (const struct mapi_stub *)
bsearch(name + 2, public_stubs, ARRAY_SIZE(public_stubs),
sizeof(public_stubs[0]), stub_compare);
}
/**
* Return offset of entrypoint for named function within dispatch table.
*/
int
_mesa_glapi_get_proc_offset(const char *funcName)
{
const struct mapi_stub *stub = _glapi_get_stub(funcName);
return stub ? stub->slot : -1;
}
/**
* Return pointer to the named function. If the function name isn't found
* in the name of static functions, try generating a new API entrypoint on
* the fly with assembly language.
*/
_glapi_proc
_mesa_glapi_get_proc_address(const char *funcName)
{
const struct mapi_stub *stub = _glapi_get_stub(funcName);
return stub ? entry_get_public(stub->slot) : NULL;
}
/**
* Return the name of the function at the given dispatch offset.
* This is only intended for debugging.
*/
const char *
_glapi_get_proc_name(unsigned offset)
{
for (unsigned i = 0; i < ARRAY_SIZE(public_stubs); ++i) {
if (public_stubs[i].slot == offset)
return &public_string_pool[public_stubs[i].name_offset];
}
return NULL;
}
/** Return pointer to new dispatch table filled with no-op functions */
struct _glapi_table *
_glapi_new_nop_table(void)
{
struct _glapi_table *table = malloc(_gloffset_COUNT * sizeof(_glapi_proc));
if (table)
memcpy(table, table_noop_array, _gloffset_COUNT * sizeof(_glapi_proc));
return table;
}
/**
* Set the current context pointer for this thread.
* The context pointer is an opaque type which should be cast to
* void from the real context pointer type.
*/
void
_mesa_glapi_set_context(void *ptr)
{
_mesa_glapi_tls_Context = ptr;
}
/**
* Get the current context pointer for this thread.
* The context pointer is an opaque type which should be cast from
* void to the real context pointer type.
*/
void *
_mesa_glapi_get_context(void)
{
return _mesa_glapi_tls_Context;
}
/**
* Set the global or per-thread dispatch table pointer.
* If the dispatch parameter is NULL we'll plug in the no-op dispatch
* table (__glapi_noop_table).
*/
void
_mesa_glapi_set_dispatch(struct _glapi_table *tbl)
{
static once_flag flag = ONCE_FLAG_INIT;
call_once(&flag, entry_patch_public);
_mesa_glapi_tls_Dispatch =
tbl ? tbl : (struct _glapi_table *)table_noop_array;
}
/**
* Return pointer to current dispatch table for calling thread.
*/
struct _glapi_table *
_mesa_glapi_get_dispatch(void)
{
return _mesa_glapi_tls_Dispatch;
}
#if defined(_WIN32) && defined(_WINDOWS_)
#error "Should not include <windows.h> here"
#endif