4 ms·
Arguably, this is a symptom of C's anemic runtime library culture. If the compiler could generate code that allocates executable memory, it could generate a st
by barrkel 7y ago
Arguably, this is a symptom of C's anemic runtime library culture.
If the compiler could generate code that allocates executable memory, it could generate a stub off in executable heap, and free it when the called function returns. This would handle nested functions in the downward funarg situation (the only one that's handled by GCC C (and Standard Pascal)).
Things would be complicated by longjmp (the stubs wouldn't be freed), but it could be handled similarly to how C++ compilers handle destructors for stack frames that are skipped by a longjmp; per the standard, the destructors aren't called, but the compiler may do so if appropriately configured.
But without a C runtime library function to allocate executable memory, the compiler is a bit stuck.
- amluto 7y agoI disagree. Generating code at runtime like this is a giant can of worms. The right fix is to have a calling convention that allows closures to be passed a context parameter, so a closure would be a function pointer and a data pointer. Basically every reasonably modern language can do this. GCC’s hack to shoehorn closures into C couldn’t. If GCC had a special function pointer type for closures, they would have worked just fine.
- saagarjha 7y agoGCC doesn’t, but Clang does: https://en.wikipedia.org/wiki/Blocks_(C_language_extension) https://en.wikipedia.org/wiki/Blocks_(C_language_extension)
- dooglius 7y agoExcept functions like qsort which are in the standard library wouldn't have such functions in the signature, so the code in the example still wouldn't work.
- amluto 7y agoglibc's qsort_r() takes a callback argument that could be used.
- shakna 7y ago> But without a C runtime library function to allocate executable memory, the compiler is a bit stuck. Whilst this can't be done in a platform-independent way, C does allow you to do this, doesn't it? void* virtualCodeAddress = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); (Or by mmapping and then calling mprotect). I believe these appeared at least in glibc 2.27 (and POSIX 2001), if not earlier, and they run at runtime. I'm not sure how legal it would be for the compiler to handle things in this way (apart from in "implementation defined" areas), but there isn't a technical reason they can't allocate executable memory at runtime. (I also believe Windows handles things similarly with VirtualAlloc & VirtualProtect).
- saagarjha 7y agoOn certain platforms there would be no equivalent function.
- shakna 7y agoYes, it cannot be done in a platform-independent way. That's normal for quite a range of things that C is still more than capable of doing. quadmath isn't supported by every architecture or platform. That doesn't mean the compiler is stuck and can't make use of it on the platforms that do support it. > Whilst this can't be done in a platform-independent way, C does allow you to do this, doesn't it?
- JoshTriplett 7y agoMany platforms won't let you allocate memory with both PROT_WRITE and PROT_EXEC. More portable JIT engines either map memory writable to write out code and then remap it read-only and executable before executing it, or map the same memory into two separate virtual addresses, one writable and one executable.
- dooglius 7y agoNo, the problem is that such a function is impossible to implement; any function that allocates memory can fail when no memory is available, and if the call fails there is no recourse in order to proceed per the spec. The compiler could easily create stub functions that call syscalls without the standard library's involvement if it wanted to (it needs to support freestanding environments, after all).
- saagarjha 7y agoAny function call can fail already: if you’ve overflowed the stack there’s not much you can do.
- dooglius 7y agoTrue, but for reliable programs, generally a separate tool will be used to statically ensure this can't happen (e.g. checkstack.pl for the Linux kernel), and these existing tools wouldn't know to parse this a new alternative allocation structure.