Load pushes the given args, env and aux vector to the stack using the well-known format for a new executable. It returns the start and end of the argument and environment vectors.
(args []string, env []string, aux Auxv)
| 137 | // well-known format for a new executable. It returns the start and end |
| 138 | // of the argument and environment vectors. |
| 139 | func (s *Stack) Load(args []string, env []string, aux Auxv) (StackLayout, error) { |
| 140 | l := StackLayout{} |
| 141 | |
| 142 | // Make sure we start with a 16-byte alignment. |
| 143 | s.Align(16) |
| 144 | |
| 145 | // Push the environment vector so the end of the argument vector is adjacent to |
| 146 | // the beginning of the environment vector. |
| 147 | // While the System V abi for x86_64 does not specify an ordering to the |
| 148 | // Information Block (the block holding the arg, env, and aux vectors), |
| 149 | // support features like setproctitle(3) naturally expect these segments |
| 150 | // to be in this order. See: https://www.uclibc.org/docs/psABI-x86_64.pdf |
| 151 | // page 29. |
| 152 | l.EnvvEnd = s.Bottom |
| 153 | envAddrs := make([]hostarch.Addr, len(env)) |
| 154 | for i := len(env) - 1; i >= 0; i-- { |
| 155 | if _, err := s.PushNullTerminatedByteSlice([]byte(env[i])); err != nil { |
| 156 | return StackLayout{}, err |
| 157 | } |
| 158 | envAddrs[i] = s.Bottom |
| 159 | } |
| 160 | l.EnvvStart = s.Bottom |
| 161 | |
| 162 | // Push our strings. |
| 163 | l.ArgvEnd = s.Bottom |
| 164 | argAddrs := make([]hostarch.Addr, len(args)) |
| 165 | for i := len(args) - 1; i >= 0; i-- { |
| 166 | if _, err := s.PushNullTerminatedByteSlice([]byte(args[i])); err != nil { |
| 167 | return StackLayout{}, err |
| 168 | } |
| 169 | argAddrs[i] = s.Bottom |
| 170 | } |
| 171 | l.ArgvStart = s.Bottom |
| 172 | |
| 173 | // We need to align the arguments appropriately. |
| 174 | // |
| 175 | // We must finish on a 16-byte alignment, but we'll play it |
| 176 | // conservatively and finish at 32-bytes. It would be nice to be able |
| 177 | // to call Align here, but unfortunately we need to align the stack |
| 178 | // with all the variable sized arrays pushed. So we just need to do |
| 179 | // some calculations. |
| 180 | argvSize := s.Arch.Width() * uint(len(args)+1) |
| 181 | envvSize := s.Arch.Width() * uint(len(env)+1) |
| 182 | auxvSize := s.Arch.Width() * 2 * uint(len(aux)+1) |
| 183 | total := hostarch.Addr(argvSize) + hostarch.Addr(envvSize) + hostarch.Addr(auxvSize) + hostarch.Addr(s.Arch.Width()) |
| 184 | expectedBottom := s.Bottom - total |
| 185 | if expectedBottom%32 != 0 { |
| 186 | s.Bottom -= expectedBottom % 32 |
| 187 | } |
| 188 | |
| 189 | // Push our auxvec. |
| 190 | // NOTE: We need an extra zero here per spec. |
| 191 | // The Push function will automatically terminate |
| 192 | // strings and arrays with a single null value. |
| 193 | auxv := make([]hostarch.Addr, 0, len(aux)*2+1) |
| 194 | for _, a := range aux { |
| 195 | auxv = append(auxv, hostarch.Addr(a.Key), a.Value) |
| 196 | } |
nothing calls this directly
no test coverage detected