From 00787b503f2e0cb0705fcfaa0205e3ca41c4a669 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Wed, 26 Feb 2020 16:21:41 -0800 Subject: [PATCH 1/2] src: start the .text section with an asm symbol We create an object file in assembly which introduces the symbol `__node_text_start` into the .text section and place the resulting object file as the first file the linker encounters. We do this to ensure that we can recognize the boundaries of the .text section when attempting to establish the address range to map to large pages. Additionally, we rename the section containing the remapping code from `.lpstub` to `lpstub` so as to take advantage of the linker's feature whereby it inserts the symbol `__start_lpstub` when the section's name can be rendered as a valid C variable. We need this symbol in order to avoid self-mapping the remapping code to large pages, because doing so would cause the process to crash. --- node.gyp | 20 ++++++++++++++++++++ src/large_pages/node_large_page.cc | 29 +++++++++++++++-------------- src/large_pages/node_text_start.S | 5 +++++ 3 files changed, 40 insertions(+), 14 deletions(-) create mode 100644 src/large_pages/node_text_start.S diff --git a/node.gyp b/node.gyp index 1e928262ac8b74..84b6d89209c5d2 100644 --- a/node.gyp +++ b/node.gyp @@ -313,6 +313,19 @@ }, 'targets': [ + { + 'target_name': 'node_text_start', + 'type': 'none', + 'conditions': [ + [ 'OS=="linux" and ' + 'target_arch=="x64"', { + 'type': 'static_library', + 'sources': [ + 'src/large_pages/node_text_start.S' + ] + }], + ] + }, { 'target_name': '<(node_core_target_name)', 'type': 'executable', @@ -498,6 +511,13 @@ 'src/node_snapshot_stub.cc' ], }], + [ 'OS=="linux" and ' + 'target_arch=="x64"', { + 'dependencies': [ 'node_text_start' ], + 'ldflags+': [ + '<(PRODUCT_DIR)/obj.target/node_text_start/src/large_pages/node_text_start.o' + ] + }], ], }, # node_core_target_name { diff --git a/src/large_pages/node_large_page.cc b/src/large_pages/node_large_page.cc index a72cb65bb65674..92e66f0b62e753 100644 --- a/src/large_pages/node_large_page.cc +++ b/src/large_pages/node_large_page.cc @@ -71,7 +71,11 @@ #if defined(__linux__) extern "C" { -extern char __executable_start; +// This symbol must be declared weak because this file becomes part of all +// Node.js targets (like node_mksnapshot, node_mkcodecache, and cctest) and +// those files do not supply the symbol. +extern char __attribute__((weak)) __node_text_start; +extern char __start_lpstub; } // extern "C" #endif // defined(__linux__) @@ -121,6 +125,8 @@ struct text_region FindNodeTextRegion() { std::string dev; char dash; uintptr_t start, end, offset, inode; + uintptr_t node_text_start = reinterpret_cast(&__node_text_start); + uintptr_t lpstub_start = reinterpret_cast(&__start_lpstub); ifs.open("/proc/self/maps"); if (!ifs) { @@ -144,21 +150,16 @@ struct text_region FindNodeTextRegion() { std::string pathname; iss >> pathname; - if (start != reinterpret_cast(&__executable_start)) + if (permission != "r-xp") continue; - // The next line is our .text section. - if (!std::getline(ifs, map_line)) - break; - - iss = std::istringstream(map_line); - iss >> std::hex >> start; - iss >> dash; - iss >> std::hex >> end; - iss >> permission; + if (node_text_start < start || node_text_start >= end) + continue; - if (permission != "r-xp") - break; + start = node_text_start; + if (lpstub_start > start && lpstub_start <= end) { + end = lpstub_start; + } char* from = reinterpret_cast(hugepage_align_up(start)); char* to = reinterpret_cast(hugepage_align_down(end)); @@ -318,7 +319,7 @@ static bool IsSuperPagesEnabled() { // d. If successful copy the code there and unmap the original region int #if !defined(__APPLE__) -__attribute__((__section__(".lpstub"))) +__attribute__((__section__("lpstub"))) #else __attribute__((__section__("__TEXT,__lpstub"))) #endif diff --git a/src/large_pages/node_text_start.S b/src/large_pages/node_text_start.S new file mode 100644 index 00000000000000..1609b254f0495a --- /dev/null +++ b/src/large_pages/node_text_start.S @@ -0,0 +1,5 @@ +.text +.align 0x2000 +.global __node_text_start +.hidden __node_text_start +__node_text_start: From 174b6bab43207abc0368999cc505222ec964eeb1 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Fri, 28 Feb 2020 07:49:43 -0800 Subject: [PATCH 2/2] Remove braces around single-statement if-body Co-Authored-By: Ben Noordhuis --- src/large_pages/node_large_page.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/large_pages/node_large_page.cc b/src/large_pages/node_large_page.cc index 92e66f0b62e753..31d85c1734a63c 100644 --- a/src/large_pages/node_large_page.cc +++ b/src/large_pages/node_large_page.cc @@ -157,9 +157,8 @@ struct text_region FindNodeTextRegion() { continue; start = node_text_start; - if (lpstub_start > start && lpstub_start <= end) { + if (lpstub_start > start && lpstub_start <= end) end = lpstub_start; - } char* from = reinterpret_cast(hugepage_align_up(start)); char* to = reinterpret_cast(hugepage_align_down(end));