kernel_elf_parser/user_stack.rs
1//! Initialize the user stack for the application
2//!
3//! The structure of the user stack is described in the following figure:
4//! position content size (bytes) + comment
5//! ------------------------------------------------------------------------
6//! stack pointer -> [ argc = number of args ] 8
7//! [ argv[0] (pointer) ] 8 (program name)
8//! [ argv[1] (pointer) ] 8
9//! [ argv[..] (pointer) ] 8 * x
10//! [ argv[n - 1] (pointer) ] 8
11//! [ argv[n] (pointer) ] 8 (= NULL)
12//! [ envp[0] (pointer) ] 8
13//! [ envp[1] (pointer) ] 8
14//! [ envp[..] (pointer) ] 8
15//! [ envp[term] (pointer) ] 8 (= NULL)
16//! [ auxv[0] (Elf32_auxv_t) ] 16
17//! [ auxv[1] (Elf32_auxv_t) ] 16
18//! [ auxv[..] (Elf32_auxv_t) ] 16
19//! [ auxv[term] (Elf32_auxv_t) ] 16 (= AT_NULL vector)
20//! [ padding ] 0 - 16
21//! [ argument ASCIIZ strings ] >= 0
22//! [ environment ASCIIZ str. ] >= 0
23//!
24//! (0xbffffff8) [ end marker ] 8 (= NULL)
25//!
26//! (0xc0000000) < bottom of stack > 0 (virtual)
27//!
28//! More details can be found in the link: <https://articles.manugarg.com/aboutelfauxiliaryvectors.html>
29
30use alloc::{collections::VecDeque, string::String, vec::Vec};
31
32use zerocopy::IntoBytes;
33
34use crate::auxv::{AuxEntry, AuxType};
35
36/// Generate initial stack frame for user stack
37///
38/// # Arguments
39///
40/// * `args` - Arguments of the application
41/// * `envs` - Environment variables of the application
42/// * `auxv` - Auxiliary vectors of the application
43/// * `sp` - Highest address of the stack
44///
45/// # Return
46///
47/// * [`Vec<u8>`] - Initial stack frame of the application
48///
49/// # Notes
50///
51/// The detailed format is described in <https://articles.manugarg.com/aboutelfauxiliaryvectors.html>
52pub fn app_stack_region(args: &[String], envs: &[String], auxv: &[AuxEntry], sp: usize) -> Vec<u8> {
53 let mut data = VecDeque::new();
54 let mut push = |src: &[u8]| -> usize {
55 data.extend(src.iter().cloned());
56 data.rotate_right(src.len());
57 sp - data.len()
58 };
59
60 // define a random string with 16 bytes
61 let random_str_pos = push("0123456789abcdef".as_bytes());
62 // Push arguments and environment variables
63 let envs_slice: Vec<_> = envs
64 .iter()
65 .map(|env| {
66 push(b"\0");
67 push(env.as_bytes())
68 })
69 .collect();
70 let argv_slice: Vec<_> = args
71 .iter()
72 .map(|arg| {
73 push(b"\0");
74 push(arg.as_bytes())
75 })
76 .collect();
77 let padding_null = "\0".repeat(8);
78 let sp = push(padding_null.as_bytes());
79
80 push(&b"\0".repeat(sp % 16));
81
82 // Align stack to 16 bytes by padding if needed.
83 // We will push following 8-byte items into stack:
84 // - auxv (each entry is 2 * usize, so item count = auxv.len() * 2)
85 // - envp (len + 1 for NULL terminator)
86 // - argv (len + 1 for NULL terminator)
87 // - argc (1 item)
88 // Total items = auxv.len() * 2 + (envs.len() + 1) + (args.len() + 1) + 1
89 // = auxv.len() * 2 + envs.len() + args.len() + 3
90 // If odd, the stack top will not be aligned to 16 bytes unless we add 8-byte
91 // padding
92 if (envs.len() + args.len() + 3) & 1 != 0 {
93 push(padding_null.as_bytes());
94 }
95
96 // Push auxiliary vectors
97 let mut has_random = false;
98 let mut has_execfn = false;
99 for entry in auxv.iter() {
100 if entry.get_type() == AuxType::RANDOM {
101 has_random = true;
102 }
103 if entry.get_type() == AuxType::EXECFN {
104 has_execfn = true;
105 }
106 if has_random && has_execfn {
107 break;
108 }
109 }
110 push(auxv.as_bytes());
111 if !has_random {
112 push(AuxEntry::new(AuxType::RANDOM, random_str_pos).as_bytes());
113 }
114 if !has_execfn {
115 push(AuxEntry::new(AuxType::EXECFN, argv_slice[0]).as_bytes());
116 }
117
118 // Push the argv and envp pointers
119 push(padding_null.as_bytes());
120 push(envs_slice.as_bytes());
121 push(padding_null.as_bytes());
122 push(argv_slice.as_bytes());
123 // Push argc
124 let sp = push(args.len().as_bytes());
125
126 assert!(sp % 16 == 0);
127
128 let mut result = Vec::with_capacity(data.len());
129 let (first, second) = data.as_slices();
130 result.extend_from_slice(first);
131 result.extend_from_slice(second);
132 result
133}