1818use std:: env;
1919use std:: fs:: File ;
2020use std:: io:: Write ;
21- use std:: io:: { BufRead , BufReader } ;
2221use std:: path:: PathBuf ;
22+ use std:: process:: Command ;
2323
2424use crate :: Error ;
2525
@@ -67,20 +67,27 @@ pub enum LinkerType {
6767///
6868pub struct Linker {
6969 linker_type : LinkerType ,
70+ ftrace_buf_size : Option < usize > ,
7071}
7172
7273impl Linker {
7374 /// Construct a Linker by manually specific the type of linker, you may use
7475 /// `auto`, it would detect current linker automatically.
7576 pub fn new ( linker_type : LinkerType ) -> Self {
76- Self { linker_type }
77+ Self {
78+ linker_type,
79+ ftrace_buf_size : None ,
80+ }
7781 }
7882 /// Construct a Linker by auto detect the type of linker, try `new` function
7983 /// if our detection mismatch.
8084 pub fn auto ( ) -> Self {
81- Self {
82- linker_type : Self :: auto_detect_linker_type ( ) ,
83- }
85+ Self :: new ( Self :: auto_detect_linker_type ( ) )
86+ }
87+ /// Set the ftrace buffer size
88+ pub fn with_ftrace_buf_size ( mut self , ftrace_buf_size : usize ) -> Self {
89+ self . ftrace_buf_size = Some ( ftrace_buf_size) ;
90+ self
8491 }
8592 /// Handle all the linking stuff.
8693 ///
@@ -106,9 +113,9 @@ impl Linker {
106113 LinkerType :: Ld => println ! ( "cargo:rustc-link-arg=--sort-section=alignment" ) ,
107114 } ;
108115 let mut dyn_list = File :: create ( out_dir. join ( "dyn_list" ) ) ?;
109- write ! (
116+ writeln ! (
110117 dyn_list,
111- "{{ __elf_phdr_info; trace_ext_prefix; trace_level; ta_head; }};\n "
118+ "{{ __elf_phdr_info; trace_ext_prefix; trace_level; ta_head; }};"
112119 ) ?;
113120 match self . linker_type {
114121 LinkerType :: Cc => println ! ( "cargo:rustc-link-arg=-Wl,--dynamic-list=dyn_list" ) ,
@@ -129,53 +136,129 @@ impl Linker {
129136 // cargo passes TARGET as env to the build scripts
130137 const ENV_TARGET : & str = "TARGET" ;
131138 println ! ( "cargo:rerun-if-env-changed={}" , ENV_TARGET ) ;
132- let mut aarch64_flag = true ;
133139 match env:: var ( ENV_TARGET ) {
134140 Ok ( ref v) if v == "arm-unknown-linux-gnueabihf" || v == "arm-unknown-optee" => {
135141 match self . linker_type {
136142 LinkerType :: Cc => println ! ( "cargo:rustc-link-arg=-Wl,--no-warn-mismatch" ) ,
137143 LinkerType :: Ld => println ! ( "cargo:rustc-link-arg=--no-warn-mismatch" ) ,
138144 } ;
139- aarch64_flag = false ;
140145 }
141146 _ => { }
142147 } ;
143148
144- let f = BufReader :: new ( File :: open ( ta_dev_kit_dir. join ( "src/ta.ld.S" ) ) ?) ;
145- let ta_lds_file_path = out_dir. join ( "ta.lds" ) ;
146- let mut ta_lds = File :: create ( ta_lds_file_path. clone ( ) ) ?;
147- for line in f. lines ( ) {
148- let l = line?;
149-
150- if aarch64_flag {
151- if l. starts_with ( '#' )
152- || l == "OUTPUT_FORMAT(\" elf32-littlearm\" )"
153- || l == "OUTPUT_ARCH(arm)"
154- {
155- continue ;
156- }
157- } else {
158- if l. starts_with ( '#' )
159- || l == "OUTPUT_FORMAT(\" elf64-littleaarch64\" )"
160- || l == "OUTPUT_ARCH(aarch64)"
161- {
162- continue ;
163- }
164- }
165-
166- if l == "\t . = ALIGN(4096);" {
167- write ! ( ta_lds, "\t . = ALIGN(65536);\n " ) ?;
168- } else {
169- write ! ( ta_lds, "{}\n " , l) ?;
170- }
149+ let link_script_dest = out_dir. join ( "ta.lds" ) ;
150+ let link_script = self . generate_new_link_script ( ta_dev_kit_dir) ?;
151+ if !std:: fs:: read ( link_script_dest. as_path ( ) )
152+ . is_ok_and ( |v| v. as_slice ( ) == link_script. as_bytes ( ) )
153+ {
154+ std:: fs:: write ( link_script_dest. as_path ( ) , link_script. as_bytes ( ) ) ?;
171155 }
172156
157+ Self :: change_default_page_size ( ) ;
173158 println ! ( "cargo:rustc-link-search={}" , out_dir. display( ) ) ;
174- println ! ( "cargo:rerun-if-changed={}" , ta_lds_file_path . display( ) ) ;
175- println ! ( "cargo:rustc-link-arg=-T{}" , ta_lds_file_path . display( ) ) ;
159+ println ! ( "cargo:rerun-if-changed={}" , link_script_dest . display( ) ) ;
160+ println ! ( "cargo:rustc-link-arg=-T{}" , link_script_dest . display( ) ) ;
176161 Ok ( ( ) )
177162 }
178163
164+ // Correcting ELF segment alignment discrepancy between Rust and C, and in
165+ // the linker script provided by OP-TEE, the alignment are set to 0x1000.
166+ //
167+ // There is a mismatch in the ELF segment alignment between the Rust and
168+ // C builds.
169+ // The C-compiled binary correctly uses an alignment of 0x1000 (4KB),
170+ // which is required for OP-TEE compatibility. However, the
171+ // Rust-generated ELF defaults to 0x10000 (64KB).
172+ // To resolve this, we need to adjust the Rust linker parameters to
173+ // match the C alignment.
174+ //
175+ // example of C build elf header:
176+ // Elf file type is DYN (Position-Independent Executable file)
177+ // Entry point 0x2f4
178+ // There are 4 program headers, starting at offset 64
179+ //
180+ // Program Headers:
181+ // Type Offset VirtAddr PhysAddr
182+ // FileSiz MemSiz Flags Align
183+ // LOAD 0x0000000000001000 0x0000000000000000 0x0000000000000000
184+ // 0x00000000000191b8 0x00000000000191b8 R E 0x1000
185+ // LOAD 0x000000000001b000 0x000000000001a000 0x000000000001a000
186+ // 0x00000000000006c4 0x000000000000bf80 RW 0x1000
187+ // DYNAMIC 0x000000000001b000 0x000000000001a000 0x000000000001a000
188+ // 0x0000000000000110 0x0000000000000110 RW 0x8
189+ // GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
190+ // 0x0000000000000000 0x0000000000000000 RW 0x10
191+ //
192+ // example of Rust build elf header:
193+ // Elf file type is DYN (Position-Independent Executable file)
194+ // Entry point 0x18d8
195+ // There are 5 program headers, starting at offset 64
196+ //
197+ // Program Headers:
198+ // Type Offset VirtAddr PhysAddr
199+ // FileSiz MemSiz Flags Align
200+ // LOAD 0x0000000000010000 0x0000000000000000 0x0000000000000000
201+ // 0x000000000001c89c 0x0000000000028150 RWE 0x10000
202+ // DYNAMIC 0x000000000002c000 0x000000000001c000 0x000000000001c000
203+ // 0x0000000000000170 0x0000000000000170 RW 0x8
204+ // NOTE 0x000000000002c4b0 0x000000000001c4b0 0x000000000001c4b0
205+ // 0x0000000000000044 0x0000000000000044 R 0x4
206+ // GNU_EH_FRAME 0x0000000000024b54 0x0000000000014b54 0x0000000000014b54
207+ // 0x0000000000000e6c 0x0000000000000e6c R 0x4
208+ // GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
209+ // 0x0000000000000000 0x0000000000000000 RW 0x10
210+ fn change_default_page_size ( ) {
211+ println ! ( "cargo:rustc-link-arg=-z" ) ;
212+ println ! ( "cargo:rustc-link-arg=max-page-size=0x1000" ) ;
213+ println ! ( "cargo:rustc-link-arg=-z" ) ;
214+ println ! ( "cargo:rustc-link-arg=common-page-size=0x1000" ) ;
215+ }
216+
217+ fn generate_new_link_script ( & self , ta_dev_kit_dir : PathBuf ) -> Result < String , Error > {
218+ let link_script_template_path = ta_dev_kit_dir. join ( "src/ta.ld.S" ) ;
219+ println ! ( "cargo:rerun-if-changed={}" , link_script_template_path. display( ) ) ;
220+
221+ let link_script_output = {
222+ const ENV_CC : & str = "CC" ;
223+ println ! ( "cargo:rerun-if-env-changed={}" , ENV_CC ) ;
224+
225+ let cc_cmd = env:: var ( ENV_CC ) . unwrap_or ( "cc" . to_string ( ) ) ;
226+ let mut tmp = Command :: new ( cc_cmd) ;
227+ tmp. args ( [
228+ "-E" ,
229+ "-P" ,
230+ "-x" ,
231+ "c" ,
232+ link_script_template_path. to_str ( ) . expect ( "infallible" ) ,
233+ ] ) ;
234+ const ENV_TARGET_ARCH : & str = "CARGO_CFG_TARGET_ARCH" ;
235+ println ! ( "cargo:rerun-if-env-changed={}" , ENV_TARGET_ARCH ) ;
236+ match env:: var ( ENV_TARGET_ARCH ) ?. as_str ( ) {
237+ "riscv32" => {
238+ tmp. arg ( "-DRV32=1" ) ;
239+ }
240+ "riscv64" => {
241+ tmp. arg ( "-DRV64=1" ) ;
242+ }
243+ "arm" => {
244+ tmp. arg ( "-DARM32=1" ) ;
245+ }
246+ "aarch64" => {
247+ tmp. arg ( "-DARM64=1" ) ;
248+ }
249+ _ => { }
250+ } ;
251+ if let Some ( ftrace_buf_size) = self . ftrace_buf_size {
252+ tmp. arg ( format ! ( "-DCFG_FTRACE_BUF_SIZE={}" , ftrace_buf_size) ) ;
253+ }
254+ tmp
255+ }
256+ . output ( ) ?
257+ . stdout ;
258+ let link_script_text = String :: from_utf8 ( link_script_output) ?;
259+ Ok ( link_script_text)
260+ }
261+
179262 fn auto_detect_linker_type ( ) -> LinkerType {
180263 const ENV_RUSTC_LINKER : & str = "RUSTC_LINKER" ;
181264 println ! ( "cargo:rerun-if-env-changed={}" , ENV_RUSTC_LINKER ) ;
0 commit comments