flat assembler
Message board for the users of flat assembler.
Index
> Linux > [SOLVED] Can a '.text' section of an ELF binary be 'rwx'? |
| Author |
|
|
Jessé 13 Jun 2026, 06:00
Hello,
I did some trials with 'elf64.inc' original file from fasm2 headers, to figure out what appears to be the main reason it does not even try to set 'writeable executable' flags under a section: trying to do this under a '.text' section, which will be the main executable section of your dynamic address ELF, simply doesn't work, apparently. I tried many things, but the resulting executable was always 'r-x' flags for the '.text' section. Has anyone tried something else to achieve a 'rwx' '.text' section? My workaround is as follows, but it is done at runtime, not compile time, so the section starts as compiled with 'r-x' flags set: Code: ; Self modifying code section example: it kind of replaces the missing '_code rwx' functionality, ; apparently unavailable to dynamic ELF '.text' section. ; After succeeded mprotect() call, this '.text' section behaves the same as '_code rwx'. format ELF64 include 'fastcall.inc' include 'stdmacros.inc' include 'stdio.inc' _code Start entry: lea rdi, [$] mov r10, 0_FFFF_FFFF_FFFF_F000h and rdi, r10 mprotect(rdi, 4096, (PROT_READ or PROT_WRITE or PROT_EXEC)); test eax, eax jz @f fprintf(*stderr, &errfmt, "failed: "); perror(NULL); exit(1); @@ fprintf(*stderr, &errfmt, "succeeded!"\n); signal(SIGINT, &.break); @@ inc [count] usleep(500'000); test [flags], 1 jnz .end fprintf(*stdout, <13,"Code section counter value: %lu",0>, *count); fflush(*stdout); jmp @b .end: fprintf(*stdout, "%s"\n "Finished."\n, <8,8," ",0>); exit(0); .break: or [flags], 1 ret errfmt xb 'Change memory protection %s', 0 count xq 0 flags xb 1111_1110b ; To compile: ; ; > ./build.sh code.rwx-dyn ; ; And then, run it: ; ; > ./code.rwx-dyn ; ; A good (and tested) way to see the change, is to look using edb-debugger under 'View->Memory Regions' ; before and after that mprotect() call, looking at the page address of that 'Start' entry point. To ease understanding, that whole '_code' line macro from this example translates to: Code: section '.text' executable align 16 public Start Start: lea rdi, [$] Thanks in advance if anyone can help, so I can apply an improvement (not too useful, but an improvement anyways) on this beauty. Last edited by Jessé on 16 Jun 2026, 07:41; edited 1 time in total |
|||
|
|
Jessé 13 Jun 2026, 13:00
I mean when making dynamic address executables, called PIE.
With static ones, no problem at all. But for static, I mean the ones using segments, not sections, in fasm2 using 'format ELF64 executable 3' statement. I also got this problem when making a 'nasm' assembler version, same situation: create a 'rwx' section at the source, PIE executable linked with 'ld', and, when compiling, that section just become 'r-x' only. But I suppose that this could be a problem on how I link using 'ld', perhaps. I'll check it later. I must add that I still have not checked the intermediate '.o' object file, which is the actual fasm2/nasm part on it. Thanks anyways, the fact that you're actually using a section, but not named '.text', may give me a clue on where to look at. |
|||
|
|
Jessé 13 Jun 2026, 14:17
I have confirmed (I guess) that the '.text' section name is a protected resource, probably by the linker as I said.
And also figured out that I misread the original fasm2 section macro at 'format/elf64.inc' file (the second macro, not the first), which is doing its stuff properly, correctly setting any of the section flags. The code below works fine: Code: format ELF64 public Start extrn exit section '.code' writeable executable align 16 Start: dec [count] mov edi, [count] sub rsp, 8 jmp PLT.exit align 4 count dd 1 The code below "seg faults" itself, because it tries to write a variable in a read-execute segment, as it is now named '.text': Code: format ELF64 public Start extrn exit section '.text' writeable executable align 16 Start: dec [count] mov edi, [count] sub rsp, 8 jmp PLT.exit align 4 count dd 1 Compiled with: Quote:
So, that's the problem. Any name other than '.text' appears to work properly, as I also have tried '.rwx'. Now, I have a plan for that feature I talk before. |
|||
|
|
revolution 13 Jun 2026, 23:05
Jessé wrote: Any name other than '.text' appears to work properly, as I also have tried '.rwx'. Also, this kind of thing tends to become a target for AVs to trigger on. Anyone making better code gets punished by the AVs panicking over anything that used different tools. |
|||
|
|
Jessé 15 Jun 2026, 10:08
I'm trying to understand better the situation regarding the specifics about section names and 'ld' (GNU linker), and have found that the linker follows some kind of "script" to generate the final binary, and, yes, there is an even worse problem that occurs when binary does not have '.text' section: according to my attempts, if the binary doesn't have a '.text' section, a lot of things regarding symbol relocations isn't included in the binary, and one coding without a named '.text' section, for example, will not be able to use 'stdout' symbol directly, whenever binary is of type dynamic.
Yes, modern software (and modern C) sucks, no doubt. Fully agreed. It seems that we need another linker (so far, I need to look elsewhere for other linkers to test), but, I will try to see if I can find anything that can be adjusted with 'ld' and, if found, I will post it here. And, as always, fasm2 is doing its part flawlessly, I've checked with a hex editor, and the flag 'writeable' alongside with 'alloc' and 'execute' is at the object section correctly. |
|||
|
|
sylware 15 Jun 2026, 13:00
The issue is ELF itself (same for microslope PE+): we now know that nowadays ELF is hardcore obsolete on modern CPU micro-architectures.
I am currently working with a different exe/dynamic lib format now (my own which is so simple, one RFC will be enough), but I will need to build system interface dynamic libraries (vulkan and libasound)... and the actual REAL pain is mostly... drum roll... c++ code! (which makes me hate computer languages with ultra complex syntax and/or runtime even more). |
|||
|
|
Jessé 16 Jun 2026, 06:54
I got something that - to a certain extent - I think is worth sharing with you all: I may say that problem is solved when I use 'mold' linker instead of GNU 'ld': it makes the section '.text' with RWX flags - as I stated in my object file generated with fasm2 - and, as a very welcoming extra, the final executable is quite small, compared to the maximum you've got from 'ld'.
Example: Code: format ELF64 purge extrn? ; Just a slightly modified version of Tomasz' standard fasm2 macro, which also sets GOT.label size at definition macro extrn? declaration* namespace ELF local sym,gsym,psym element sym : relocatable * (-1) + SYMBOL_INDEX element gsym : GOT + SYMBOL_INDEX element psym : PLT + SYMBOL_INDEX match str =as? name:size, declaration label name:size at sym label GOT.name:size at gsym label PLT.name at psym SYMBOL_NAME = string str SYMBOL_SIZE = size else match name:size, declaration label name:size at sym label GOT.name:size at gsym label PLT.name at psym SYMBOL_NAME = `name SYMBOL_SIZE = size else match str =as? name, declaration label name at sym label GOT.name:size at gsym label PLT.name at psym SYMBOL_NAME = string str SYMBOL_SIZE = 0 else label declaration at sym label GOT.declaration:8 at gsym label PLT.declaration at psym SYMBOL_NAME = `declaration SYMBOL_SIZE = 0 end match store STRING_POSITION at symbol_table : Elf64_Sym.st_name + SYMBOL_INDEX * sizeof Elf64_Sym store SYMBOL_NAME : lengthof SYMBOL_NAME at string_table:STRING_POSITION STRING_POSITION = STRING_POSITION + lengthof SYMBOL_NAME + 1 store SYMBOL_SIZE at symbol_table : Elf64_Sym.st_size + SYMBOL_INDEX * sizeof Elf64_Sym store STT_NOTYPE + STB_GLOBAL shl 4 at symbol_table : Elf64_Sym.st_info + SYMBOL_INDEX * sizeof Elf64_Sym SYMBOL_INDEX = SYMBOL_INDEX + 1 end namespace end macro SIG_INT = 2 public Start extrn exit extrn fflush extrn fprintf extrn signal extrn stderr:8 extrn stdout:8 extrn usleep section '.text' writeable executable align 16 Start: lea rsi, [.break] mov edi, SIG_INT call [GOT.signal] lea rsi, [msg.start] mov rdi, [stdout] mov al, 0 call [GOT.fprintf] .count: inc [count] mov edi, 500'000 call [GOT.usleep] test [flags], 1 jnz .end mov edx, [count] lea rsi, [stats] mov rdi, [stdout] xor al, al call [GOT.fprintf] mov rdi, [stdout] call [GOT.fflush] jmp .count .end: lea rsi, [erase.ctrl_c] mov rdi, [stdout] sub al, al call [GOT.fprintf] xor edi, edi sub rsp, 8 jmp PLT.exit .break: or [flags], 1 ret align 4 count dd 0 flags db 1111_1110b msg.start db 'Starting...',10,0 stats db 13,'Code section counter is: %lu ',0 erase.ctrl_c db 8,8,32,32,10,0 The above code, when linked with 'ld', results in a 13440 bytes executable that fails (for reasons mentioned above, related to the dictatorship behvior regarding not making my '.text' section as I requested). When linked with 'mold', the final executable is only 3488 bytes, and, it worked flawlessly, with section '.text' being RWX and any supported extra section also being there and properly set up. The only minor problem with 'mold' is that it tags itself inside every binary in a '.comment' section, but this can be easily removed with: Quote: > strip -R .comment exec.name By the way, 'mold' command line is quite similar to 'ld', and I let my following command line as a reference for ones using it: Quote:
So, to answer myself: yes, it is possible to have a named '.text' section as read-write-execute, of course not recommended. And also, @sylware: not a problem with ELF itself, this time. But I'm very interest in you developing a new format. Keep it going, and share with us if possible. Thank you! |
|||
|
|
Jessé 21 Jun 2026, 11:35
I must add that 'lld' linker (invoked as 'ld.lld' on Linux) also got it right, with a slightly better executable than 'mold' (even smaller than what 'mold' delivered).
Save caveat as 'mold' with relation to tag itself in a '.comment' section, so, same procedure for the one who wants his binaries cleaner. |
|||
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2026, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.