3 ms·
> When I attempted to link without that, the linker complained that it couldn't find main. Interesting that it worked for you without that. My guess would be b
by byuu 10y ago
> When I attempted to link without that, the linker complained that it couldn't find main. Interesting that it worked for you without that.
My guess would be because I also had main.o on the command line? It looks like yours didn't have that.
> LLVM's lld has some support for linker scripts, plenty enough to do things like this
Hmmm, well just throwing out alternative ideas ... I could try something like this:
__attribute__((aligned(4096)))
static const unsigned char co_swap_function[4096] = { ... };
VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges);
//or
mprotect((void*)base, size, PROT_READ | PROT_EXEC);
The theory being that the const will put it into either .rdata or .rodata (since nobody can decide on one or the other it seems); and then by forcing the alignment to a page boundary and also filling a page boundary, we make sure the VirtualProtect or mprotect call won't affect anything other than our co_swap function. But even if it does, it'll most likely be more read-only data, and it's not the end of the world if that gets marked executable.
The downside is of course that the page size isn't really known at compile-time. On ?nix, it's a run-time call to sysconf(_SC_PAGESIZE); but on Windows I'm not sure how to get that value. However, I'm pretty sure it's going to be 4K on any x86/amd64 systems.
So, these seem to be all of our possible options:
1. we use inline assembly; and now you require a specific assembler (MSVC and GCC inline ASM syntax are totally different) or additional tools like nasm/yasm. I really don't understand why at least three people have favored this solution now; but since they haven't elaborated any reasons, I'll just have to politely agree to disagree here :/
2. we use __attribute__((section)), and get unsuppressible warning messages, and the command also won't work with MSVC.
3. we use __attribute__((section)) with our own name, and use a linker script to suppress the warning message, losing compatibility with MSVC.
4. we use __attribute__((aligned(4096))), risk the page size being wrong, and the attribute won't work with MSVC.
5. we use #include <stdalign.h> [when _MSC_VER isn't defined] + alignas(4096), risk the page size being wrong, and require C11 instead of C89 to compile. [_Alignas probably isn't going to be in MSVC due to their hatred of C99 and above.]
For the latter two, we can have #ifndef/#define LIBCO_PAGE_SIZE 4096, for convenient command-line overrides.
Probably the most pragmatic route will be to support multiple options and let the user override if one of them doesn't work out on their platform for some reason.
EDIT: here we go:
SYSTEM_INFO si;
GetSystemInfo(&si);
int page_size = si.dwPageSize;
Then for good measure, we throw in:
assert(LIBCO_PAGE_SIZE == si.dwPageSize); //or for ?nix, == sysconf(_SC_PAGESIZE)
- JoshTriplett 10y agoMSVC also has mechanisms to manipulate where data ends up in the final binary; you'd just need to use those mechanisms on Windows. But yes, approach 5 seems the most portable.