https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ed8355222976c1834ba15…
commit ed8355222976c1834ba15446782c3f6dfd5ec0a8
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Sat Jan 19 23:28:17 2019 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Sun Jan 27 00:51:25 2019 +0100
[FREELDR] Introduce a MSVC "linker script" file that centralizes the
commands for defining section-limit symbols, and the ordering and merging of PE sections,
and the necessary CMake code to use it. (#1224)
As the MSVC linker alone doesn't permit such control, the file uses
ASM language (C can alternatively be used), together with extra linker
command-line switches.
It is pre-processed 3 times: first for generating the ASM code, second
for the C code and the third time for generating the linker response
file.
In our case, the ASM code defines the __bss_start__ and __bss_end__
symbols that allow us to find the limits of the .bss section (which is
by the way automatically appended to the .data section by the MSVC linker).
The C code is used to specify the list of linker switches that can be
passed through the `#pragma comment(linker, ...)' directive (the can be
alternatively specified in the linker response section).
Finally the linker response section contains all the linker switches
that cannot be specified with the `#pragma comment(linker, ...)'
directive.
Using all this we can recycle the BSS initialization code, that has been
written originally for GCC only, also for the MSVC builds.
Also, remove the outdated .text16 section merging.
---
boot/freeldr/freeldr/CMakeLists.txt | 80 ++++++++++++++++++++++++++++--
boot/freeldr/freeldr/arch/amd64/entry.S | 21 +++++++-
boot/freeldr/freeldr/arch/i386/entry.S | 31 ++++++------
boot/freeldr/freeldr/freeldr_i386.lds | 5 ++
boot/freeldr/freeldr/freeldr_i386.msvc.lds | 78 +++++++++++++++++++++++++++++
boot/freeldr/freeldr/include/mm.h | 10 ++--
6 files changed, 199 insertions(+), 26 deletions(-)
diff --git a/boot/freeldr/freeldr/CMakeLists.txt b/boot/freeldr/freeldr/CMakeLists.txt
index ff7731e6ba..88c1c2a528 100644
--- a/boot/freeldr/freeldr/CMakeLists.txt
+++ b/boot/freeldr/freeldr/CMakeLists.txt
@@ -5,6 +5,74 @@ if(SEPARATE_DBG)
set(CMAKE_LDR_PE_HELPER_STANDARD_LIBRARIES "-lgcc" CACHE STRING
"Standard C Libraries")
endif()
+if(NOT MSVC)
+###
+### For GCC
+###
+function(add_linker_script _target _linker_script_file)
+ get_filename_component(_file_full_path ${_linker_script_file} ABSOLUTE)
+ add_target_link_flags(${_target} "-Wl,-T,${_file_full_path}")
+
+ # Unfortunately LINK_DEPENDS is ignored in non-Makefile generators (for now...)
+ # See also
http://www.cmake.org/pipermail/cmake/2010-May/037206.html
+ add_target_property(${_target} LINK_DEPENDS ${_file_full_path})
+endfunction()
+
+else()
+###
+### For MSVC
+###
+function(add_linker_script _target _linker_script_file)
+ get_filename_component(_file_full_path ${_linker_script_file} ABSOLUTE)
+ get_filename_component(_file_name ${_linker_script_file} NAME)
+ set(_generated_file_path_prefix
"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_target}.dir/${_file_name}")
+
+ # Generate the ASM module containing sections specifications and layout.
+ set(_generated_file "${_generated_file_path_prefix}.S")
+ add_custom_command(
+ OUTPUT ${_generated_file}
+ COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${_file_full_path}" "${_generated_file}"
+ DEPENDS ${_file_full_path})
+ set_source_files_properties(${_generated_file} PROPERTIES LANGUAGE "ASM"
GENERATED TRUE)
+ add_asm_files(freeldr_linker_file ${_generated_file})
+
+ # Generate the C module containing extra sections specifications and layout,
+ # as well as comment-type linker #pragma directives.
+ set(_generated_file "${_generated_file_path_prefix}.c")
+ add_custom_command(
+ OUTPUT ${_generated_file}
+ COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${_file_full_path}" "${_generated_file}"
+ DEPENDS ${_file_full_path})
+ set_source_files_properties(${_generated_file} PROPERTIES LANGUAGE "C"
GENERATED TRUE)
+ list(APPEND freeldr_linker_file ${_generated_file})
+
+ # Add both files to the sources of the target.
+ target_sources(${_target} PRIVATE ${freeldr_linker_file})
+
+ # Create the additional linker response file.
+ set(_generated_file "${_generated_file_path_prefix}.rsp")
+ if(USE_CLANG_CL)
+ set(_no_std_includes_flag "-nostdinc")
+ else()
+ set(_no_std_includes_flag "/X")
+ endif()
+ add_custom_command(
+ #OUTPUT ${_generated_file}
+ TARGET ${_target} PRE_LINK
+ COMMAND ${CMAKE_C_COMPILER} /nologo ${_no_std_includes_flag} /D__LINKER__ /EP /c
"${_file_full_path}" > "${_generated_file}"
+ DEPENDS ${_file_full_path}
+ VERBATIM)
+ set_source_files_properties(${_generated_file} PROPERTIES GENERATED TRUE)
+ add_target_link_flags(${_target} "@${_generated_file}")
+
+ # Unfortunately LINK_DEPENDS is ignored in non-Makefile generators (for now...)
+ # See also
http://www.cmake.org/pipermail/cmake/2010-May/037206.html
+ add_target_property(${_target} LINK_DEPENDS ${_generated_file})
+endfunction()
+
+endif()
+
+
if(MSVC)
# We don't need hotpatching
replace_compile_flags("/hotpatch" " ")
@@ -238,12 +306,16 @@ if(MSVC)
add_target_link_flags(freeldr_pe "/ignore:4078 /ignore:4254 /DRIVER")
add_target_link_flags(freeldr_pe_dbg "/ignore:4078 /ignore:4254
/DRIVER")
else()
- add_target_link_flags(freeldr_pe "/ignore:4078 /ignore:4254 /DRIVER /FIXED
/ALIGN:0x400 /SECTION:.text,ERW /SECTION:.data,RW /MERGE:.text16=.text /MERGE:INIT=.text
/MERGE:.data=.text /MERGE:.rdata=.text /MERGE:.bss=.text")
- add_target_link_flags(freeldr_pe_dbg "/ignore:4078 /ignore:4254 /DRIVER
/FIXED /ALIGN:0x400 /SECTION:.text,ERW /SECTION:.data,RW /MERGE:.text16=.text
/MERGE:INIT=.text /MERGE:.data=.text /MERGE:.rdata=.text /MERGE:.bss=.text")
+ add_target_link_flags(freeldr_pe "/ignore:4078 /ignore:4254 /DRIVER /FIXED
/FILEALIGN:0x200 /ALIGN:0x200")
+ add_linker_script(freeldr_pe freeldr_i386.msvc.lds)
+ add_target_link_flags(freeldr_pe_dbg "/ignore:4078 /ignore:4254 /DRIVER
/FIXED /FILEALIGN:0x200 /ALIGN:0x200")
+ add_linker_script(freeldr_pe_dbg freeldr_i386.msvc.lds)
endif()
else()
- add_target_link_flags(freeldr_pe
"-Wl,--strip-all,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lds")
- add_target_link_flags(freeldr_pe_dbg
"-Wl,--exclude-all-symbols,--file-alignment,0x1000,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lds")
+ add_target_link_flags(freeldr_pe
"-Wl,--strip-all,--exclude-all-symbols,--file-alignment,0x200,--section-alignment,0x200")
+ add_linker_script(freeldr_pe freeldr_i386.lds)
+ add_target_link_flags(freeldr_pe_dbg
"-Wl,--exclude-all-symbols,--file-alignment,0x200,--section-alignment,0x200")
+ add_linker_script(freeldr_pe_dbg freeldr_i386.lds)
endif()
set_image_base(freeldr_pe 0x10000)
diff --git a/boot/freeldr/freeldr/arch/amd64/entry.S
b/boot/freeldr/freeldr/arch/amd64/entry.S
index 075778f884..e5620bd300 100644
--- a/boot/freeldr/freeldr/arch/amd64/entry.S
+++ b/boot/freeldr/freeldr/arch/amd64/entry.S
@@ -3,6 +3,12 @@
#include <arch/pc/x86common.h>
EXTERN BootMain:PROC
+// EXTERN cmdline:DWORD
+
+#ifdef _USE_ML
+EXTERN __bss_start__:FWORD
+EXTERN __bss_end__:FWORD
+#endif
.code64
@@ -40,13 +46,24 @@ FrldrStartup:
mov eax, dword ptr [BSS_RealModeEntry]
mov dword ptr [AddressOfRealModeEntryPoint], eax
- /* GO! */
+ /* Clean out BSS */
+ xor rax, rax
+ mov rdi, offset __bss_start__
+ mov rcx, offset __bss_end__ + 7
+ sub rcx, rdi
+ shr rcx, 3
+ rep stosq
+
+ /* Pass the command line to BootMain */
+ // mov rcx, offset cmdline
xor rcx, rcx
+
+ /* GO! */
call BootMain
/* We should never get here */
stop:
- jmp stop
+ jmp short stop
nop
nop
diff --git a/boot/freeldr/freeldr/arch/i386/entry.S
b/boot/freeldr/freeldr/arch/i386/entry.S
index 90a40272d4..6e2b1826de 100644
--- a/boot/freeldr/freeldr/arch/i386/entry.S
+++ b/boot/freeldr/freeldr/arch/i386/entry.S
@@ -25,6 +25,12 @@ EXTERN _BootMain:PROC
EXTERN _InitIdt:PROC
EXTERN _i386Idt:DWORD
//EXTERN _i386idtptr:FWORD
+// EXTERN cmdline:DWORD
+
+#ifdef _USE_ML
+EXTERN __bss_start__:DWORD
+EXTERN __bss_end__:DWORD
+#endif
.code32
@@ -59,6 +65,8 @@ ContinueAddress:
_FrldrStartup:
+ASSUME /*CS:_TEXT,*/ DS:_DATA, ES:_DATA, FS:_DATA, GS:_DATA, SS:_DATA
+
/* Store BootDrive and BootPartition */
mov byte ptr ds:[_FrldrBootDrive], dl
xor eax, eax
@@ -69,11 +77,7 @@ _FrldrStartup:
mov eax, dword ptr ds:[BSS_RealModeEntry]
mov dword ptr ds:[SwitchToReal16Address], eax
- /* Initialize the idt */
- call _InitIdt
-
-#ifndef _USE_ML
- /* Clean out bss */
+ /* Clean out BSS */
xor eax, eax
mov edi, offset __bss_start__
mov ecx, offset __bss_end__ + 3
@@ -81,11 +85,12 @@ _FrldrStartup:
shr ecx, 2
rep stosd
+ /* Initialize the idt */
+ call _InitIdt
+
/* Pass the command line to BootMain */
- mov eax, offset cmdline
-#else
+ // mov eax, offset cmdline
xor eax, eax
-#endif
/* GO! */
push eax
@@ -93,7 +98,7 @@ _FrldrStartup:
/* We should never get here */
stop:
- jmp stop
+ jmp short stop
nop
nop
@@ -181,7 +186,7 @@ SwitchToReal:
mov ss, ax
/* Save 32-bit stack pointer */
- mov dword ptr [stack32], esp
+ mov dword ptr ds:[stack32], esp
/* jmp to 16-bit segment to set the limit correctly */
.byte HEX(0ea) // jmp far RMODE_CS:switch_to_real16
@@ -236,11 +241,7 @@ gdtptr:
.word HEX(27) /* Limit */
.long gdt /* Base Address */
-/* Real-mode IDT pointer */
-rmode_idtptr:
- .word HEX(3ff) /* Limit */
- .long 0 /* Base Address */
-
+// See _i386IdtDescriptor
PUBLIC i386idtptr
i386idtptr:
.word 255 /* Limit */
diff --git a/boot/freeldr/freeldr/freeldr_i386.lds
b/boot/freeldr/freeldr/freeldr_i386.lds
index 5cb2cb6c7b..56df8f63ee 100644
--- a/boot/freeldr/freeldr/freeldr_i386.lds
+++ b/boot/freeldr/freeldr/freeldr_i386.lds
@@ -12,6 +12,11 @@ SECTIONS
*(SORT(.rdata*))
}
+ /*
+ * LD needs an explicit .edata block to make the binary correctly export
+ * symbols, otherwise, if .edata is merged with another section (e.g. .rdata)
+ * the exports are not exported!
+ */
.edata BLOCK(__file_alignment__) :
{
*(.edata)
diff --git a/boot/freeldr/freeldr/freeldr_i386.msvc.lds
b/boot/freeldr/freeldr/freeldr_i386.msvc.lds
new file mode 100644
index 0000000000..061221f2b8
--- /dev/null
+++ b/boot/freeldr/freeldr/freeldr_i386.msvc.lds
@@ -0,0 +1,78 @@
+/*****************************************************************************\
+ *** MSVC Linker Script File -- Sections specifications & layout ***
+\*****************************************************************************/
+
+#ifndef _MSC_VER
+#error This file must be used only with the MSVC compiler and linker.
+#endif
+
+#if defined(__LINKER__)
+/*********************************\
+ ** Linker response file **
+\*********************************/
+
+// /LAST:.bss
+/LAST:.data
+
+#elif !defined(_USE_ML)
+/*********************************\
+ ** C Linker #pragma directives **
+\*********************************/
+
+/*
+ * Notes about automatic LINK.EXE behaviour that cannot be changed:
+ *
+ * - If a .data section is present, the .bss section is appended to it in case
+ * both of these have either Initialized or Uninitialized data (which is the
+ * case, unless one has manually modified the attributes).
+ *
+ * - If the /DRIVER flag is NOT used, and if both the .rdata and the .edata
+ * sections (read-only data and exports, respectively) have the same
+ * attributes, the .edata section is appended to the .rdata section.
+ * Otherwise they are kept separated, unless an explicit /MERGE is used.
+ */
+
+#pragma comment(linker, "/SECTION:.text,ERW /SECTION:.data,RW /MERGE:INIT=.text
/MERGE:.edata=.rdata")
+
+#endif
+
+
+#if defined(_USE_ML) // && !defined(__LINKER__)
+/************************\
+ ** ASM definitions **
+\************************/
+
+#include <asm.inc>
+
+/*
+#pragma bss_seg(".bss")
+// __declspec(allocate(".bss"))
+void* __bss_start__;
+#pragma bss_seg()
+*/
+_BSS1 SEGMENT 'BSS' ALIAS('.bss')
+PUBLIC __bss_start__
+__bss_start__:
+ .long ?
+_BSS1 ENDS
+
+/*
+#pragma bss_seg(".bss$ZZZ")
+// __declspec(allocate(".bss$ZZZ"))
+void* __bss_end__;
+#pragma bss_seg()
+*/
+_BSS2 SEGMENT 'BSS' ALIAS('.bss$ZZZ')
+PUBLIC __bss_end__
+__bss_end__:
+ .long ?
+_BSS2 ENDS
+
+END
+
+#elif !defined(__LINKER__)
+/************************\
+ ** C definitions **
+\************************/
+
+#endif
diff --git a/boot/freeldr/freeldr/include/mm.h b/boot/freeldr/freeldr/include/mm.h
index adc13d0ebf..e86424f17a 100644
--- a/boot/freeldr/freeldr/include/mm.h
+++ b/boot/freeldr/freeldr/include/mm.h
@@ -21,15 +21,15 @@
extern char __ImageBase;
#ifdef __GNUC__
-/* .text, .edata and .bss */
+/* .text/.data/.rdata, .edata and .bss */
#define FREELDR_SECTION_COUNT 3
#else
#ifdef _M_AMD64
-/* .text and .pdata */
-#define FREELDR_SECTION_COUNT 2
+/* .text, .rdata/.edata, .pdata and .data/.bss */
+#define FREELDR_SECTION_COUNT 4
#else
-/* .text and .edata */
-#define FREELDR_SECTION_COUNT 2
+/* .text, .rdata/.edata and .data/.bss */
+#define FREELDR_SECTION_COUNT 3
#endif
#endif