diff --git a/core/libs/CMakeLists.txt b/core/libs/CMakeLists.txt index cb240d7dd..6abb0fdd0 100644 --- a/core/libs/CMakeLists.txt +++ b/core/libs/CMakeLists.txt @@ -53,6 +53,9 @@ set(LIBS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(${LIBC_DIR} ${CMAKE_CURRENT_BINARY_DIR}/prx/libc) target_include_directories(libc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) configure_windows_unwind(libc) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_link_options(libc PRIVATE LINKER:-z,now) +endif() set(UNPATCHED_DIR ${CMAKE_CURRENT_BINARY_DIR}/libs/unpatched) set(PATCHED_DIR ${CMAKE_CURRENT_BINARY_DIR}/libs) @@ -102,6 +105,9 @@ foreach(LIB_DIR ${LIBS_DIRS}) else() target_link_libraries(${LIB_NAME} PRIVATE libkernel libc) endif() + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_link_options(${LIB_NAME} PRIVATE LINKER:-z,now) + endif() if(WIN32 AND LIB_NAME STREQUAL "libSceNet") target_link_libraries(${LIB_NAME} PRIVATE ws2_32) target_compile_definitions(${LIB_NAME} PRIVATE _WIN32_WINNT=0x0602) diff --git a/core/libs/tests/Fiber.cpp b/core/libs/tests/Fiber.cpp index 707a59a80..da0721409 100644 --- a/core/libs/tests/Fiber.cpp +++ b/core/libs/tests/Fiber.cpp @@ -81,6 +81,30 @@ void APS5_VABI CheckedEntry(std::uint64_t, std::uint64_t) { for (;;) sceFiberReturnToThread(0, &received); } +constexpr std::size_t SmallContextSize = 2048; +constexpr unsigned char SmallGuardFill = 0xa5; +alignas(16) std::array g_smallArea; +FiberStorage g_smallStorage; + +void APS5_VABI SmallEntry(std::uint64_t, std::uint64_t) { + std::uint64_t received = 0; + for (;;) sceFiberReturnToThread(0, &received); +} + +void RunSmallContextFirst() { + auto* small = reinterpret_cast(&g_smallStorage); + auto* context = g_smallArea.data() + g_smallArea.size() - SmallContextSize; + g_smallArea.fill(SmallGuardFill); + Require(sceFiberReturnToThread(0, nullptr) == FiberErrorPermission, "return to thread outside a fiber"); + Require(_sceFiberInitializeImpl_nid_postfix(small, "small", SmallEntry, 0, context, SmallContextSize, nullptr, 0) == 0, "initialize small"); + Require(sceFiberRun_nid_postfix(small, 0, nullptr) == 0, "first fiber run of the process on a 2 KiB context"); + Require(sceFiberRun_nid_postfix(small, 0, nullptr) == 0, "resume on a 2 KiB context"); + Require(sceFiberFinalize(small) == 0, "finalize small"); + for (auto* byte = g_smallArea.data(); byte != context; ++byte) { + Require(*byte == SmallGuardFill, "nothing is written below a 2 KiB context"); + } +} + [[gnu::noinline]] std::int32_t RunFirst(std::uint64_t* returned) { g_threadFramePointer = reinterpret_cast(__builtin_frame_address(0)); const std::int32_t result = sceFiberRun_nid_postfix(g_first, 100, returned); @@ -91,6 +115,7 @@ void APS5_VABI CheckedEntry(std::uint64_t, std::uint64_t) { } int main() { + RunSmallContextFirst(); FiberObject* self = nullptr; Require(sceFiberGetSelf(&self) == FiberErrorPermission, "no fiber on the thread"); Require(_sceFiberInitializeImpl_nid_postfix(g_first, "first", FirstEntry, 11, g_firstContext.data(), g_firstContext.size(), nullptr, 0) == 0, "initialize first");