4 ms·
Wow, that's very neat! Thank you! Does Clang support this as well? It looks like I don't need the main.o(.text) line either, which is good because that would b
by byuu 10y ago
Wow, that's very neat! Thank you! Does Clang support this as well?
It looks like I don't need the main.o(.text) line either, which is good because that would be a large burden on users of the library.
Also, just noting for others, I had to use .text : { libco.o(.rdata); } since my char array was const.
- pdw 10y agoThe attribute approach seems a lot more convenient: const unsigned char add[] __attribute__((section("text"))) = { 0x48, 0x89, 0xf8, /* mov %rdi,%rax */ 0x48, 0x01, 0xf0, /* add %rsi,%rax */ 0xc3, /* retq */ };
- byuu 10y agoInteresting ... with section("text"), it crashes. With section(".text"), it works, but spews out this: <gibberish>.s: Assembler messages: <gibberish>.s:155: Warning: Ignoring changed section attributes for .text However, it does compile and work :/
- JoshTriplett 10y ago"text" isn't the right section name; that'll create a new data section named "text", and then you'll segfault trying to execute out of a data section. Specifying ".text" causes the toolchain to attempt to create a data section named ".text", which causes the "changed section attributes" message; the array then correctly ends up in the executable ".text" section, though. I'd like to see a way to declare a section without attempting to make it a data section, but I think the compiler folks' answer to that would probably be "use a linker script". And I don't know a way to disable the warning.
- JoshTriplett 10y ago> Wow, that's very neat! Thank you! Glad I could help. Thank you for building awesome software. > Does Clang support this as well? Clang supports __attribute__((section)). For linker script support, it'd depend on what linker you use. GNU ld and gold have complete support for linker scripts. LLVM's lld has some support for linker scripts, plenty enough to do things like this, though it may lack some features that GNU ld and gold support. > It looks like I don't need the main.o(.text) line either, which is good because that would be a large burden on users of the library. When I attempted to link without that, the linker complained that it couldn't find main. Interesting that it worked for you without that. You can also use wildcards to match all object files, if that helps, and then use "ld -T thescript.ld *.o" to link. > Also, just noting for others, I had to use .text : { libco.o(.rdata); } since my char array was const. Sadly, read-only sections vary a bit more; some compilers use .rdata, some use .rodata. You could use __attribute__((section)) to explicitly put the array in a specific section, then name that section in the linker script; that avoids the warning and any platform-specific inconsistency.
- 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)