feat: extend user and waitanyfast
This commit is contained in:
1 parent
baece1a2b0
commit
40b71851f5
3 files changed
+64
-5
No files matched your search
+23
-5
@@ -1,18 +1,36 @@
|
|||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
|
|
||||||
|
/* Two PT_LOAD segments, not one: text+rodata read+execute only (FLAGS(5)
|
||||||
|
= PF_R|PF_X), data+bss read+write only (FLAGS(6) = PF_R|PF_W) -- real
|
||||||
|
W^X for every binary this links, mirroring the kernel's own linker.ld
|
||||||
|
(:text/:rodata/:data). elf.c's elfLoad reads each segment's own p_flags
|
||||||
|
(elfSegmentPagingFlags) to map it with paging.h's pageWrite/pageNoExecute
|
||||||
|
accordingly, so a binary that writes into its own string literals or
|
||||||
|
jumps into its own .data now takes a real, catchable SIGSEGV instead of
|
||||||
|
silently succeeding the way one shared RWX segment always allowed --
|
||||||
|
see user/elfwritevictim.c and user/elfexecvictim.c for the live proof. */
|
||||||
PHDRS
|
PHDRS
|
||||||
{
|
{
|
||||||
load PT_LOAD FILEHDR PHDRS FLAGS(7);
|
text PT_LOAD FILEHDR PHDRS FLAGS(5);
|
||||||
|
data PT_LOAD FLAGS(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = USER_BASE + SIZEOF_HEADERS;
|
. = USER_BASE + SIZEOF_HEADERS;
|
||||||
|
|
||||||
.text : { *(.text .text.*) } :load
|
.text : { *(.text .text.*) } :text
|
||||||
.rodata : { *(.rodata .rodata.*) } :load
|
.rodata : { *(.rodata .rodata.*) } :text
|
||||||
.data : { *(.data .data.*) } :load
|
|
||||||
.bss : { *(.bss .bss.*) *(COMMON) } :load
|
/* Fresh page for .data: the two PT_LOAD segments above must never
|
||||||
|
share a page, or the CPU would have to apply the union of both
|
||||||
|
segments' flags to that shared page, quietly reintroducing a
|
||||||
|
writable+executable (or writable .rodata) page exactly where this
|
||||||
|
split exists to remove one. */
|
||||||
|
. = ALIGN(4096);
|
||||||
|
|
||||||
|
.data : { *(.data .data.*) } :data
|
||||||
|
.bss : { *(.bss .bss.*) *(COMMON) } :data
|
||||||
|
|
||||||
/DISCARD/ :
|
/DISCARD/ :
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only ever spawned by waitanytest.c. Exits immediately with no sleep at
|
||||||
|
* all, so waitanytest.c's very first userWaitAny() call is overwhelmingly
|
||||||
|
* likely to find this one already Dead (the other child, waitanyslow.c,
|
||||||
|
* cannot possibly have finished its own userSleep by then) -- proves
|
||||||
|
* threadJoinAnyChild's waitScanFoundDead path picks up an already-dead
|
||||||
|
* child without ever needing to block at all.
|
||||||
|
*/
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
print("waitanyfast: start, pid=");
|
||||||
|
printDec(userGetpid());
|
||||||
|
print("\n");
|
||||||
|
print("waitanyfast: exiting now\n");
|
||||||
|
return 44;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only ever spawned by waitanytest.c. Sleeps a real, non-trivial amount
|
||||||
|
* before exiting -- long enough that waitanytest.c's own userWaitAny()
|
||||||
|
* calls cannot possibly race past it by luck: its first call happens
|
||||||
|
* essentially immediately after spawning both children (see
|
||||||
|
* waitanytest.c's own file comment), so this thread genuinely cannot be
|
||||||
|
* Dead yet by the time that first call runs. That is what forces
|
||||||
|
* waitanytest.c's SECOND userWaitAny() call to take threadJoinAnyChild's
|
||||||
|
* waitScanNoneDead branch and actually block through the real
|
||||||
|
* retry-syscall path, rather than getting lucky and finding it already
|
||||||
|
* dead too.
|
||||||
|
*/
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
print("waitanyslow: start, pid=");
|
||||||
|
printDec(userGetpid());
|
||||||
|
print("\n");
|
||||||
|
userSleep(150);
|
||||||
|
print("waitanyslow: exiting now\n");
|
||||||
|
return 33;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user