Update to v101r18 release.

byuu says:

Changelog:

  - added 30 new PAL games to icarus (courtesy of Mikerochip)
  - new version of libco no longer requires mprotect nor W|X permissions
  - nall: default C compiler to -std=c11 instead of -std=c99
  - nall: use `-fno-strict-aliasing` during compilation
  - updated nall/certificates (hopefully for the last time)
  - updated nall/http to newer coding conventions
  - nall: improve handling of range() function

I didn't really work on higan at all, this is mostly just a release
because lots of other things have changed.

The most interesting is `-fno-strict-aliasing` ... basically, it joins
`-fwrapv` as being "stop the GCC developers from doing *really* evil
shit that could lead to security vulnerabilities or instabilities."

For the most part, it's a ~2% speed penalty for higan. Except for the
Sega Genesis, where it's a ~10% speedup. I have no idea how that's
possible, but clearly something's going very wrong with strict aliasing
on the Genesis core.

So ... it is what it is. If you need the performance for the non-Genesis
cores, you can turn it off in your builds. But I'm getting quite sick of
C++'s "surprises" and clever compiler developers, so I'm keeping it on
in all of my software going forward.
This commit is contained in:
Tim Allen
2016-09-14 21:55:53 +10:00
parent 750af6ebc3
commit 45a725e4b7
9 changed files with 421 additions and 412 deletions

32
amd64.c
View File

@@ -1,15 +1,12 @@
/*
libco.amd64 (2015-06-19)
libco.amd64 (2016-09-14)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
//Win64 only: provides a substantial speed-up, but will thrash XMM regs
//do not use this unless you are certain your application won't use SSE
//#define LIBCO_AMD64_NO_SSE
#include "settings.h"
#include <assert.h>
#include <stdlib.h>
@@ -22,9 +19,14 @@ static thread_local long long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (*co_swap)(cothread_t, cothread_t) = 0;
#ifdef LIBCO_MPROTECT
alignas(4096)
#else
section(text)
#endif
#ifdef _WIN32
/* ABI: Win64 */
static unsigned char co_swap_function[] = {
static const unsigned char co_swap_function[4096] = {
0x48, 0x89, 0x22, /* mov [rdx],rsp */
0x48, 0x8b, 0x21, /* mov rsp,[rcx] */
0x58, /* pop rax */
@@ -36,7 +38,7 @@ static void (*co_swap)(cothread_t, cothread_t) = 0;
0x4c, 0x89, 0x6a, 0x30, /* mov [rdx+48],r13 */
0x4c, 0x89, 0x72, 0x38, /* mov [rdx+56],r14 */
0x4c, 0x89, 0x7a, 0x40, /* mov [rdx+64],r15 */
#if !defined(LIBCO_AMD64_NO_SSE)
#if !defined(LIBCO_NO_SSE)
0x0f, 0x29, 0x72, 0x50, /* movaps [rdx+ 80],xmm6 */
0x0f, 0x29, 0x7a, 0x60, /* movaps [rdx+ 96],xmm7 */
0x44, 0x0f, 0x29, 0x42, 0x70, /* movaps [rdx+112],xmm8 */
@@ -57,7 +59,7 @@ static void (*co_swap)(cothread_t, cothread_t) = 0;
0x4c, 0x8b, 0x69, 0x30, /* mov r13,[rcx+48] */
0x4c, 0x8b, 0x71, 0x38, /* mov r14,[rcx+56] */
0x4c, 0x8b, 0x79, 0x40, /* mov r15,[rcx+64] */
#if !defined(LIBCO_AMD64_NO_SSE)
#if !defined(LIBCO_NO_SSE)
0x0f, 0x28, 0x71, 0x50, /* movaps xmm6, [rcx+ 80] */
0x0f, 0x28, 0x79, 0x60, /* movaps xmm7, [rcx+ 96] */
0x44, 0x0f, 0x28, 0x41, 0x70, /* movaps xmm8, [rcx+112] */
@@ -75,13 +77,15 @@ static void (*co_swap)(cothread_t, cothread_t) = 0;
#include <windows.h>
void co_init() {
static void co_init() {
#ifdef LIBCO_MPROTECT
DWORD old_privileges;
VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges);
#endif
}
#else
/* ABI: SystemV */
static unsigned char co_swap_function[] = {
static const unsigned char co_swap_function[4096] = {
0x48, 0x89, 0x26, /* mov [rsi],rsp */
0x48, 0x8b, 0x27, /* mov rsp,[rdi] */
0x58, /* pop rax */
@@ -103,11 +107,13 @@ static void (*co_swap)(cothread_t, cothread_t) = 0;
#include <unistd.h>
#include <sys/mman.h>
void co_init() {
static void co_init() {
#ifdef LIBCO_MPROTECT
unsigned long long addr = (unsigned long long)co_swap_function;
unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
mprotect((void*)base, size, PROT_READ | PROT_EXEC);
#endif
}
#endif

16
arm.c
View File

@@ -1,11 +1,12 @@
/*
libco.arm (2015-06-18)
libco.arm (2016-09-14)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#include "settings.h"
#include <assert.h>
#include <stdlib.h>
@@ -20,17 +21,24 @@ static thread_local unsigned long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (*co_swap)(cothread_t, cothread_t) = 0;
static unsigned long co_swap_function[] = {
#ifdef LIBCO_MPROTECT
alignas(4096)
#else
section(text)
#endif
static const unsigned long co_swap_function[1024] = {
0xe8a16ff0, /* stmia r1!, {r4-r11,sp,lr} */
0xe8b0aff0, /* ldmia r0!, {r4-r11,sp,pc} */
0xe12fff1e, /* bx lr */
};
void co_init() {
static void co_init() {
#ifdef LIBCO_MPROTECT
unsigned long addr = (unsigned long)co_swap_function;
unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
mprotect((void*)base, size, PROT_READ | PROT_EXEC);
#endif
}
cothread_t co_active() {

11
libco.h
View File

@@ -1,6 +1,5 @@
/*
libco
version: 0.17 (2015-06-18)
libco v18 (2016-09-14)
author: byuu
license: public domain
*/
@@ -8,14 +7,6 @@
#ifndef LIBCO_H
#define LIBCO_H
#ifdef LIBCO_C
#ifdef LIBCO_MP
#define thread_local __thread
#else
#define thread_local
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif

129
ppc.c
View File

@@ -1,33 +1,29 @@
/*
libco.ppc (2010-10-17)
libco.ppc (2016-09-14)
author: blargg
license: public domain
*/
/* PowerPC 32/64 using embedded or external asm, with optional
floating-point and AltiVec save/restore */
#define LIBCO_C
#include "libco.h"
#include "settings.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define LIBCO_MPROTECT (__unix__ && !LIBCO_PPC_ASM)
#if LIBCO_MPROTECT
#include <unistd.h>
#include <sys/mman.h>
#endif
/* State format (offsets in 32-bit words)
/* state format (offsets in 32-bit words)
+0 Pointer to swap code
Rest of function descriptor for entry function
+0 pointer to swap code
rest of function descriptor for entry function
+8 PC
+10 SP
Special regs
special registers
GPRs
FPRs
VRs
@@ -40,34 +36,23 @@ enum { stack_align = 256 };
static thread_local cothread_t co_active_handle = 0;
/**** Determine environment ****/
/* determine environment */
#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)
/* Whether function calls are indirect through a descriptor,
or are directly to function */
/* whether function calls are indirect through a descriptor, or are directly to function */
#ifndef LIBCO_PPCDESC
#if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)
#define LIBCO_PPCDESC 1
#endif
#endif
#ifdef LIBCO_PPC_ASM
#ifdef __cplusplus
extern "C"
#endif
/* Swap code is in ppc.S */
void co_swap_asm( cothread_t, cothread_t );
#define CO_SWAP_ASM( x, y ) co_swap_asm( x, y )
#ifdef LIBCO_MPROTECT
alignas(4096)
#else
/* Swap code is here in array. Please leave dieassembly comments,
as they make it easy to see what it does, and reorder instructions
if one wants to see whether that improves performance. */
static const uint32_t libco_ppc_code [] = {
section(text)
#endif
static const uint32_t libco_ppc_code[1024] = {
#if LIBCO_PPC64
0x7d000026, /* mfcr r8 */
0xf8240028, /* std r1,40(r4) */
@@ -272,86 +257,68 @@ static const uint32_t libco_ppc_code [] = {
};
#if LIBCO_PPCDESC
/* Function call goes through indirect descriptor */
#define CO_SWAP_ASM( x, y ) \
((void (*)( cothread_t, cothread_t )) (uintptr_t) x)( x, y )
/* function call goes through indirect descriptor */
#define CO_SWAP_ASM(x, y) ((void (*)(cothread_t, cothread_t))(uintptr_t)x)(x, y)
#else
/* Function call goes directly to code */
#define CO_SWAP_ASM( x, y ) \
((void (*)( cothread_t, cothread_t )) (uintptr_t) libco_ppc_code)( x, y )
/* function call goes directly to code */
#define CO_SWAP_ASM(x, y) ((void (*)(cothread_t, cothread_t))(uintptr_t)libco_ppc_code)(x, y)
#endif
#endif
static uint32_t* co_create_( unsigned size, uintptr_t entry )
{
uint32_t* t = (uint32_t*) malloc( size );
static uint32_t* co_create_(unsigned size, uintptr_t entry) {
(void)entry;
#if LIBCO_PPCDESC
if ( t )
{
/* Copy entry's descriptor */
memcpy( t, (void*) entry, sizeof (void*) * 3 );
uint32_t* t = (uint32_t*)malloc(size);
/* Set function pointer to swap routine */
#ifdef LIBCO_PPC_ASM
*(const void**) t = *(void**) &co_swap_asm;
#else
*(const void**) t = libco_ppc_code;
#endif
#if LIBCO_PPCDESC
if(t) {
memcpy(t, (void*)entry, sizeof(void*) * 3); /* copy entry's descriptor */
*(const void**)t = libco_ppc_code; /* set function pointer to swap routine */
}
#endif
return t;
}
cothread_t co_create( unsigned int size, void (*entry_)( void ) )
{
cothread_t co_create(unsigned int size, void (*entry_)(void)) {
uintptr_t entry = (uintptr_t)entry_;
uint32_t* t = NULL;
uint32_t* t = 0;
/* Be sure main thread was successfully allocated */
if ( co_active() )
{
/* be sure main thread was successfully allocated */
if(co_active()) {
size += state_size + above_stack + stack_align;
t = co_create_(size, entry);
}
if ( t )
{
if(t) {
uintptr_t sp;
int shift;
/* Save current registers into new thread, so that any special ones will
have proper values when thread is begun */
/* save current registers into new thread, so that any special ones will have proper values when thread is begun */
CO_SWAP_ASM(t, t);
#if LIBCO_PPCDESC
/* Get real address */
entry = (uintptr_t) *(void**) entry;
entry = (uintptr_t)*(void**)entry; /* get real address */
#endif
/* Put stack near end of block, and align */
/* put stack near end of block, and align */
sp = (uintptr_t)t + size - above_stack;
sp -= sp % stack_align;
/* On PPC32, we save and restore GPRs as 32 bits. For PPC64, we
/* on PPC32, we save and restore GPRs as 32 bits. for PPC64, we
save and restore them as 64 bits, regardless of the size the ABI
uses. So, we manually write pointers at the proper size. We always
uses. so, we manually write pointers at the proper size. we always
save and restore at the same address, and since PPC is big-endian,
we must put the low byte first on PPC32. */
/* If uintptr_t is 32 bits, >>32 is undefined behavior, so we do two shifts
and don't have to care how many bits uintptr_t is. */
/* if uintptr_t is 32 bits, >>32 is undefined behavior,
so we do two shifts and don't have to care how many bits uintptr_t is. */
#if LIBCO_PPC64
shift = 16;
#else
shift = 0;
#endif
/* Set up so entry will be called on next swap */
/* set up so entry will be called on next swap */
t[ 8] = (uint32_t)(entry >> shift >> shift);
t[ 9] = (uint32_t)entry;
@@ -362,45 +329,37 @@ cothread_t co_create( unsigned int size, void (*entry_)( void ) )
return t;
}
void co_delete( cothread_t t )
{
void co_delete(cothread_t t) {
free(t);
}
static void co_init_( void )
{
static void co_init_(void) {
#if LIBCO_MPROTECT
/* TODO: pre- and post-pad PPC code so that this doesn't make other
data executable and writable */
long page_size = sysconf(_SC_PAGESIZE);
if ( page_size > 0 )
{
if(page_size > 0) {
uintptr_t align = page_size;
uintptr_t begin = (uintptr_t)libco_ppc_code;
uintptr_t end = begin + sizeof libco_ppc_code;
/* Align beginning and end */
/* align beginning and end */
end += align - 1;
end -= end % align;
begin -= begin % align;
mprotect( (void*) begin, end - begin, PROT_READ | PROT_WRITE | PROT_EXEC );
mprotect((void*)begin, end - begin, PROT_READ | PROT_EXEC);
}
#endif
co_active_handle = co_create_(state_size, (uintptr_t)&co_switch);
}
cothread_t co_active()
{
if ( !co_active_handle )
co_init_();
cothread_t co_active() {
if(!co_active_handle) co_init_();
return co_active_handle;
}
void co_switch( cothread_t t )
{
void co_switch(cothread_t t) {
cothread_t old = co_active_handle;
co_active_handle = t;

36
settings.h Normal file
View File

@@ -0,0 +1,36 @@
#ifdef LIBCO_C
/*[amd64, arm, ppc, x86]:
by default, co_swap_function is marked as a text (code) section
if not supported, uncomment the below line to use mprotect instead */
/* #define LIBCO_MPROTECT */
/*[amd64]:
Win64 only: provides a substantial speed-up, but will thrash XMM regs
do not use this unless you are certain your application won't use SSE */
/* #define LIBCO_NO_SSE */
#ifdef LIBCO_C
#ifdef LIBCO_MP
#define thread_local __thread
#else
#define thread_local
#endif
#endif
#if __STDC_VERSION__ >= 201112L
#ifndef _MSC_VER
#include <stdalign.h>
#endif
#else
#define alignas(bytes)
#endif
#ifndef _MSC_VER
#define section(name) __attribute__((section("." #name "#")))
#else
#define section(name) __declspec(allocate("." #name))
#endif
/* ifdef LIBCO_C */
#endif

9
sjlj.c
View File

@@ -5,10 +5,8 @@
*/
/*
* Note this was designed for UNIX systems. Based on ideas expressed in a paper
* by Ralf Engelschall.
* For SJLJ on other systems, one would want to rewrite springboard() and
* co_create() and hack the jmb_buf stack pointer.
note this was designed for UNIX systems. Based on ideas expressed in a paper by Ralf Engelschall.
for SJLJ on other systems, one would want to rewrite springboard() and co_create() and hack the jmb_buf stack pointer.
*/
#define LIBCO_C
@@ -29,7 +27,8 @@ typedef struct {
} cothread_struct;
static thread_local cothread_struct co_primary;
static thread_local cothread_struct *creating, *co_running = 0;
static thread_local cothread_struct* creating;
static thread_local cothread_struct* co_running = 0;
static void springboard(int ignored) {
if(sigsetjmp(creating->context, 0)) {

View File

@@ -5,15 +5,15 @@
*/
/*
* WARNING: the overhead of POSIX ucontext is very high,
* assembly versions of libco or libco_sjlj should be much faster
*
* This library only exists for two reasons:
* 1 - as an initial test for the viability of a ucontext implementation
* 2 - to demonstrate the power and speed of libco over existing implementations,
* such as pth (which defaults to wrapping ucontext on unix targets)
*
* Use this library only as a *last resort*
WARNING: the overhead of POSIX ucontext is very high,
assembly versions of libco or libco_sjlj should be much faster
this library only exists for two reasons:
1: as an initial test for the viability of a ucontext implementation
2: to demonstrate the power and speed of libco over existing implementations,
such as pth (which defaults to wrapping ucontext on unix targets)
use this library only as a *last resort*
*/
#define LIBCO_C

22
x86.c
View File

@@ -1,11 +1,12 @@
/*
libco.x86 (2009-10-12)
libco.x86 (2016-09-14)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#include "settings.h"
#include <assert.h>
#include <stdlib.h>
@@ -26,8 +27,13 @@ static thread_local long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;
#ifdef LIBCO_MPROTECT
alignas(4096)
#else
section(text)
#endif
/* ABI: fastcall */
static unsigned char co_swap_function[] = {
static const unsigned char co_swap_function[4096] = {
0x89, 0x22, /* mov [edx],esp */
0x8b, 0x21, /* mov esp,[ecx] */
0x58, /* pop eax */
@@ -45,19 +51,23 @@ static unsigned char co_swap_function[] = {
#ifdef _WIN32
#include <windows.h>
void co_init() {
static void co_init() {
#ifdef LIBCO_MPROTECT
DWORD old_privileges;
VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges);
#endif
}
#else
#include <unistd.h>
#include <sys/mman.h>
void co_init() {
static void co_init() {
#ifdef LIBCO_MPROTECT
unsigned long addr = (unsigned long)co_swap_function;
unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
mprotect((void*)base, size, PROT_READ | PROT_EXEC);
#endif
}
#endif