2 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
8 * NaCl Simple/secure ELF loader (NaCl SEL).
11 #include "native_client/src/include/portability.h"
17 #include "native_client/src/include/elf_constants.h"
18 #include "native_client/src/include/elf.h"
19 #include "native_client/src/include/nacl_macros.h"
20 #include "native_client/src/include/win/mman.h"
21 #include "native_client/src/shared/platform/nacl_check.h"
22 #include "native_client/src/shared/platform/nacl_log.h"
23 #include "native_client/src/shared/platform/nacl_sync_checked.h"
24 #include "native_client/src/shared/platform/nacl_time.h"
26 #include "native_client/src/shared/srpc/nacl_srpc.h"
28 #include "native_client/src/trusted/perf_counter/nacl_perf_counter.h"
30 #include "native_client/src/trusted/reverse_service/reverse_control_rpc.h"
32 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
33 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
35 #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
36 #include "native_client/src/trusted/service_runtime/elf_util.h"
37 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
38 #include "native_client/src/trusted/service_runtime/nacl_kernel_service.h"
39 #include "native_client/src/trusted/service_runtime/nacl_runtime_host_interface.h"
40 #include "native_client/src/trusted/service_runtime/nacl_signal.h"
41 #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h"
42 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
43 #include "native_client/src/trusted/service_runtime/nacl_text.h"
44 #include "native_client/src/trusted/service_runtime/sel_memory.h"
45 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
46 #include "native_client/src/trusted/service_runtime/sel_ldr_thread_interface.h"
47 #include "native_client/src/trusted/service_runtime/sel_util.h"
48 #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
50 #if !defined(SIZE_T_MAX)
51 # define SIZE_T_MAX (~(size_t) 0)
56 * Fill from static_text_end to end of that page with halt
57 * instruction, which is at least NACL_HALT_LEN in size when no
58 * dynamic text is present. Does not touch dynamic text region, which
59 * should be pre-filled with HLTs.
61 * By adding NACL_HALT_SLED_SIZE, we ensure that the code region ends
62 * with HLTs, just in case the CPU has a bug in which it fails to
63 * check for running off the end of the x86 code segment.
65 void NaClFillEndOfTextRegion(struct NaClApp *nap) {
69 * NOTE: make sure we are not silently overwriting data. It is the
70 * toolchain's responsibility to ensure that a NACL_HALT_SLED_SIZE
73 if (0 != nap->data_start &&
74 nap->static_text_end + NACL_HALT_SLED_SIZE >
75 NaClTruncAllocPage(nap->data_start)) {
76 NaClLog(LOG_FATAL, "Missing gap between text and data for halt_sled\n");
78 if (0 != nap->rodata_start &&
79 nap->static_text_end + NACL_HALT_SLED_SIZE > nap->rodata_start) {
80 NaClLog(LOG_FATAL, "Missing gap between text and rodata for halt_sled\n");
83 if (NULL == nap->text_shm) {
85 * No dynamic text exists. Space for NACL_HALT_SLED_SIZE must
88 page_pad = (NaClRoundAllocPage(nap->static_text_end + NACL_HALT_SLED_SIZE)
89 - nap->static_text_end);
90 CHECK(page_pad >= NACL_HALT_SLED_SIZE);
91 CHECK(page_pad < NACL_MAP_PAGESIZE + NACL_HALT_SLED_SIZE);
94 * Dynamic text exists; the halt sled resides in the dynamic text
95 * region, so all we need to do here is to round out the last
96 * static text page with HLT instructions. It doesn't matter if
97 * the size of this region is smaller than NACL_HALT_SLED_SIZE --
98 * this is just to fully initialize the page, rather than (later)
99 * decoding/validating zero-filled memory as instructions.
101 page_pad = NaClRoundAllocPage(nap->static_text_end) - nap->static_text_end;
105 "Filling with halts: %08"NACL_PRIxPTR", %08"NACL_PRIxS" bytes\n",
106 nap->mem_start + nap->static_text_end,
109 NaClFillMemoryRegionWithHalt((void *)(nap->mem_start + nap->static_text_end),
112 nap->static_text_end += page_pad;
116 * Basic address space layout sanity check.
118 NaClErrorCode NaClCheckAddressSpaceLayoutSanity(struct NaClApp *nap,
119 uintptr_t rodata_end,
121 uintptr_t max_vaddr) {
122 if (0 != nap->data_start) {
123 if (data_end != max_vaddr) {
124 NaClLog(LOG_INFO, "data segment is not last\n");
125 return LOAD_DATA_NOT_LAST_SEGMENT;
127 } else if (0 != nap->rodata_start) {
128 if (NaClRoundAllocPage(rodata_end) != max_vaddr) {
130 * This should be unreachable, but we include it just for
133 * Here is why it is unreachable:
135 * NaClPhdrChecks checks the test segment starting address. The
136 * only allowed loaded segments are text, data, and rodata.
137 * Thus unless the rodata is in the trampoline region, it must
138 * be after the text. And NaClElfImageValidateProgramHeaders
139 * ensures that all segments start after the trampoline region.
141 NaClLog(LOG_INFO, "no data segment, but rodata segment is not last\n");
142 return LOAD_NO_DATA_BUT_RODATA_NOT_LAST_SEGMENT;
145 if (0 != nap->rodata_start && 0 != nap->data_start) {
146 if (rodata_end > NaClTruncAllocPage(nap->data_start)) {
147 NaClLog(LOG_INFO, "rodata_overlaps data.\n");
148 return LOAD_RODATA_OVERLAPS_DATA;
151 if (0 != nap->rodata_start) {
152 if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) > nap->rodata_start) {
153 return LOAD_TEXT_OVERLAPS_RODATA;
155 } else if (0 != nap->data_start) {
156 if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) >
157 NaClTruncAllocPage(nap->data_start)) {
158 return LOAD_TEXT_OVERLAPS_DATA;
161 if (0 != nap->rodata_start &&
162 NaClRoundAllocPage(nap->rodata_start) != nap->rodata_start) {
163 NaClLog(LOG_INFO, "rodata_start not a multiple of allocation size\n");
164 return LOAD_BAD_RODATA_ALIGNMENT;
166 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
168 * This check is necessary to make MIPS sandbox secure, as there is no NX page
169 * protection support on MIPS.
171 if (nap->rodata_start < NACL_DATA_SEGMENT_START) {
173 "rodata_start is below NACL_DATA_SEGMENT_START (0x%X) address\n",
174 NACL_DATA_SEGMENT_START);
175 return LOAD_SEGMENT_BAD_LOC;
181 void NaClLogAddressSpaceLayout(struct NaClApp *nap) {
182 NaClLog(2, "NaClApp addr space layout:\n");
183 NaClLog(2, "nap->static_text_end = 0x%016"NACL_PRIxPTR"\n",
184 nap->static_text_end);
185 NaClLog(2, "nap->dynamic_text_start = 0x%016"NACL_PRIxPTR"\n",
186 nap->dynamic_text_start);
187 NaClLog(2, "nap->dynamic_text_end = 0x%016"NACL_PRIxPTR"\n",
188 nap->dynamic_text_end);
189 NaClLog(2, "nap->rodata_start = 0x%016"NACL_PRIxPTR"\n",
191 NaClLog(2, "nap->data_start = 0x%016"NACL_PRIxPTR"\n",
193 NaClLog(2, "nap->data_end = 0x%016"NACL_PRIxPTR"\n",
195 NaClLog(2, "nap->break_addr = 0x%016"NACL_PRIxPTR"\n",
197 NaClLog(2, "nap->initial_entry_pt = 0x%016"NACL_PRIxPTR"\n",
198 nap->initial_entry_pt);
199 NaClLog(2, "nap->user_entry_pt = 0x%016"NACL_PRIxPTR"\n",
201 NaClLog(2, "nap->bundle_size = 0x%x\n", nap->bundle_size);
205 NaClErrorCode NaClAppLoadFileAslr(struct NaClDesc *ndp,
207 enum NaClAslrMode aslr_mode) {
208 NaClErrorCode ret = LOAD_INTERNAL;
209 NaClErrorCode subret = LOAD_INTERNAL;
210 uintptr_t rodata_end;
213 struct NaClElfImage *image = NULL;
214 struct NaClPerfCounter time_load_file;
215 struct NaClElfImageInfo info;
217 NaClPerfCounterCtor(&time_load_file, "NaClAppLoadFile");
219 /* NACL_MAX_ADDR_BITS < 32 */
220 if (nap->addr_bits > NACL_MAX_ADDR_BITS) {
221 ret = LOAD_ADDR_SPACE_TOO_BIG;
225 nap->stack_size = NaClRoundAllocPage(nap->stack_size);
227 /* temporay object will be deleted at end of function */
228 image = NaClElfImageNew(ndp, &subret);
229 if (NULL == image || LOAD_OK != subret) {
234 subret = NaClElfImageValidateProgramHeaders(image,
237 if (LOAD_OK != subret) {
242 if (nap->initial_nexe_max_code_bytes != 0) {
243 size_t code_segment_size = info.static_text_end - NACL_TRAMPOLINE_END;
244 if (code_segment_size > nap->initial_nexe_max_code_bytes) {
245 NaClLog(LOG_ERROR, "NaClAppLoadFileAslr: "
246 "Code segment size (%"NACL_PRIdS" bytes) exceeds limit (%"
247 NACL_PRId32" bytes)\n",
248 code_segment_size, nap->initial_nexe_max_code_bytes);
249 ret = LOAD_CODE_SEGMENT_TOO_LARGE;
254 nap->static_text_end = info.static_text_end;
255 nap->rodata_start = info.rodata_start;
256 rodata_end = info.rodata_end;
257 nap->data_start = info.data_start;
258 data_end = info.data_end;
259 max_vaddr = info.max_vaddr;
261 if (0 == nap->data_start) {
262 if (0 == nap->rodata_start) {
263 if (NaClRoundAllocPage(max_vaddr) - max_vaddr < NACL_HALT_SLED_SIZE) {
265 * if no rodata and no data, we make sure that there is space for
268 max_vaddr += NACL_MAP_PAGESIZE;
272 * no data, but there is rodata. this means max_vaddr is just
273 * where rodata ends. this might not be at an allocation
274 * boundary, and in this the page would not be writable. round
275 * max_vaddr up to the next allocation boundary so that bss will
276 * be at the next writable region.
280 max_vaddr = NaClRoundAllocPage(max_vaddr);
283 * max_vaddr -- the break or the boundary between data (initialized
284 * and bss) and the address space hole -- does not have to be at a
287 * Memory allocation will use NaClRoundPage(nap->break_addr), but
288 * the system notion of break is always an exact address. Even
289 * though we must allocate and make accessible multiples of pages,
290 * the linux-style brk system call (which returns current break on
291 * failure) permits a non-aligned address as argument.
293 nap->break_addr = max_vaddr;
294 nap->data_end = max_vaddr;
296 NaClLog(4, "Values from NaClElfImageValidateProgramHeaders:\n");
297 NaClLog(4, "rodata_start = 0x%08"NACL_PRIxPTR"\n", nap->rodata_start);
298 NaClLog(4, "rodata_end = 0x%08"NACL_PRIxPTR"\n", rodata_end);
299 NaClLog(4, "data_start = 0x%08"NACL_PRIxPTR"\n", nap->data_start);
300 NaClLog(4, "data_end = 0x%08"NACL_PRIxPTR"\n", data_end);
301 NaClLog(4, "max_vaddr = 0x%08"NACL_PRIxPTR"\n", max_vaddr);
303 /* We now support only one bundle size. */
304 nap->bundle_size = NACL_INSTR_BLOCK_SIZE;
306 nap->initial_entry_pt = NaClElfImageGetEntryPoint(image);
307 NaClLogAddressSpaceLayout(nap);
309 if (!NaClAddrIsValidEntryPt(nap, nap->initial_entry_pt)) {
310 ret = LOAD_BAD_ENTRY;
314 subret = NaClCheckAddressSpaceLayoutSanity(nap, rodata_end, data_end,
316 if (LOAD_OK != subret) {
321 NaClLog(2, "Allocating address space\n");
322 NaClPerfCounterMark(&time_load_file, "PreAllocAddrSpace");
323 NaClPerfCounterIntervalLast(&time_load_file);
324 subret = NaClAllocAddrSpaceAslr(nap, aslr_mode);
325 NaClPerfCounterMark(&time_load_file,
326 NACL_PERF_IMPORTANT_PREFIX "AllocAddrSpace");
327 NaClPerfCounterIntervalLast(&time_load_file);
328 if (LOAD_OK != subret) {
334 * Make sure the static image pages are marked writable before we try
337 NaClLog(2, "Loading into memory\n");
338 ret = NaClMprotect((void *) (nap->mem_start + NACL_TRAMPOLINE_START),
339 NaClRoundAllocPage(nap->data_end) - NACL_TRAMPOLINE_START,
340 PROT_READ | PROT_WRITE);
343 "NaClAppLoadFile: Failed to make image pages writable. "
347 subret = NaClElfImageLoad(image, ndp, nap);
348 if (LOAD_OK != subret) {
354 * NB: mem_map object has been initialized, but is empty.
355 * NaClMakeDynamicTextShared does not touch it.
357 * NaClMakeDynamicTextShared also fills the dynamic memory region
358 * with the architecture-specific halt instruction. If/when we use
359 * memory mapping to save paging space for the dynamic region and
360 * lazily halt fill the memory as the pages become
361 * readable/executable, we must make sure that the *last*
362 * NACL_MAP_PAGESIZE chunk is nonetheless mapped and written with
366 ("Replacing gap between static text and"
367 " (ro)data with shareable memory\n"));
368 subret = NaClMakeDynamicTextShared(nap);
369 NaClPerfCounterMark(&time_load_file,
370 NACL_PERF_IMPORTANT_PREFIX "MakeDynText");
371 NaClPerfCounterIntervalLast(&time_load_file);
372 if (LOAD_OK != subret) {
378 * NaClFillEndOfTextRegion will fill with halt instructions the
379 * padding space after the static text region.
381 * Shm-backed dynamic text space was filled with halt instructions
382 * in NaClMakeDynamicTextShared. This extends to the rodata. For
383 * non-shm-backed text space, this extend to the next page (and not
384 * allocation page). static_text_end is updated to include the
387 NaClFillEndOfTextRegion(nap);
389 if (nap->main_exe_prevalidated) {
390 NaClLog(2, "Main executable segment hit validation cache and mapped in,"
391 " skipping validation.\n");
394 NaClLog(2, "Validating image\n");
395 subret = NaClValidateImage(nap);
397 NaClPerfCounterMark(&time_load_file,
398 NACL_PERF_IMPORTANT_PREFIX "ValidateImg");
399 NaClPerfCounterIntervalLast(&time_load_file);
400 if (LOAD_OK != subret) {
405 NaClLog(2, "Initializing arch switcher\n");
406 NaClInitSwitchToApp(nap);
408 NaClLog(2, "Installing trampoline\n");
409 NaClLoadTrampoline(nap);
411 NaClLog(2, "Installing springboard\n");
412 NaClLoadSpringboard(nap);
415 * NaClMemoryProtection also initializes the mem_map w/ information
416 * about the memory pages and their current protection value.
418 * The contents of the dynamic text region will get remapped as
421 NaClLog(2, "Applying memory protection\n");
422 subret = NaClMemoryProtection(nap);
423 if (LOAD_OK != subret) {
428 NaClLog(2, "NaClAppLoadFile done; ");
429 NaClLogAddressSpaceLayout(nap);
432 NaClElfImageDelete(image);
434 NaClPerfCounterMark(&time_load_file, "EndLoadFile");
435 NaClPerfCounterIntervalTotal(&time_load_file);
439 NaClErrorCode NaClAppLoadFile(struct NaClDesc *ndp,
440 struct NaClApp *nap) {
441 return NaClAppLoadFileAslr(ndp, nap, NACL_ENABLE_ASLR);
444 NaClErrorCode NaClAppLoadFileDynamically(
446 struct NaClDesc *ndp,
447 struct NaClValidationMetadata *metadata) {
448 struct NaClElfImage *image = NULL;
449 NaClErrorCode ret = LOAD_INTERNAL;
451 image = NaClElfImageNew(ndp, &ret);
452 if (NULL == image || LOAD_OK != ret) {
455 ret = NaClElfImageLoadDynamically(image, nap, ndp, metadata);
456 if (LOAD_OK != ret) {
459 nap->user_entry_pt = nap->initial_entry_pt;
460 nap->initial_entry_pt = NaClElfImageGetEntryPoint(image);
463 NaClElfImageDelete(image);
467 int NaClAddrIsValidEntryPt(struct NaClApp *nap,
469 if (0 != (addr & (nap->bundle_size - 1))) {
473 return addr < nap->static_text_end;
476 int NaClAppLaunchServiceThreads(struct NaClApp *nap) {
477 struct NaClKernelService *kernel_service = NULL;
480 NaClLog(4, "NaClAppLaunchServiceThreads: Entered, nap 0x%"NACL_PRIxPTR"\n",
483 NaClNameServiceLaunch(nap->name_service);
485 if (LOAD_OK != NaClWaitForStartModuleCommand(nap)) {
489 NaClXMutexLock(&nap->mu);
490 if (NULL == nap->runtime_host_interface) {
491 nap->runtime_host_interface = malloc(sizeof *nap->runtime_host_interface);
492 if (NULL == nap->runtime_host_interface ||
493 !NaClRuntimeHostInterfaceCtor_protected(nap->runtime_host_interface)) {
494 NaClLog(LOG_ERROR, "NaClAppLaunchServiceThreads:"
495 " Failed to initialise runtime host interface\n");
499 NaClXMutexUnlock(&nap->mu);
501 kernel_service = (struct NaClKernelService *) malloc(sizeof *kernel_service);
502 if (NULL == kernel_service) {
504 "NaClAppLaunchServiceThreads: No memory for kern service\n");
508 if (!NaClKernelServiceCtor(kernel_service,
509 NaClAddrSpSquattingThreadIfFactoryFunction,
511 nap->runtime_host_interface)) {
513 "NaClAppLaunchServiceThreads: KernServiceCtor failed\n");
514 free(kernel_service);
515 kernel_service = NULL;
519 if (!NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
522 "NaClAppLaunchServiceThreads: KernService start service failed\n");
526 * NB: StartServiceThread grabbed another reference to kernel_service,
527 * used by the service thread. Closing the connection capability
528 * should cause the service thread to shut down and in turn release
532 NaClXMutexLock(&nap->mu);
533 CHECK(NULL == nap->kernel_service);
535 nap->kernel_service = kernel_service;
536 kernel_service = NULL;
537 NaClXMutexUnlock(&nap->mu);
541 NaClXMutexLock(&nap->mu);
542 if (NULL != nap->kernel_service) {
544 ("NaClAppLaunchServiceThreads: adding kernel service to"
546 (*NACL_VTBL(NaClNameService, nap->name_service)->
547 CreateDescEntry)(nap->name_service,
548 "KernelService", NACL_ABI_O_RDWR,
549 NaClDescRef(nap->kernel_service->base.bound_and_cap[1]));
551 NaClXMutexUnlock(&nap->mu);
556 * Error cleanup invariant. No service thread should be running
557 * (modulo asynchronous shutdown). Automatic variables refer to
558 * fully constructed objects if non-NULL, and when ownership is
559 * transferred to the NaClApp object the corresponding automatic
560 * variable is set to NULL.
562 NaClRefCountSafeUnref((struct NaClRefCount *) kernel_service);
566 int NaClReportExitStatus(struct NaClApp *nap, int exit_status) {
569 NaClXMutexLock(&nap->mu);
571 * If several threads are exiting/reporting signals at once, we should
572 * let only one thread to pass through. This way we can use exit code
573 * without synchronization once we know that running==0.
576 NaClXMutexUnlock(&nap->mu);
580 if (NULL != nap->runtime_host_interface) {
581 /* TODO(halyavin) update NaCl plugin to accept full exit_status value */
582 if (NACL_ABI_WIFEXITED(exit_status)) {
583 rv = (*NACL_VTBL(NaClRuntimeHostInterface, nap->runtime_host_interface)->
584 ReportExitStatus)(nap->runtime_host_interface,
585 NACL_ABI_WEXITSTATUS(exit_status));
588 * Due to cross-repository checkins, the Cr-side might not yet
589 * implement this RPC. We return whether shutdown was reported.
592 nap->exit_status = exit_status;
594 NaClXCondVarSignal(&nap->cv);
596 NaClXMutexUnlock(&nap->mu);
601 uintptr_t NaClGetInitialStackTop(struct NaClApp *nap) {
603 * We keep the top of useful memory a page below the top of the
604 * sandbox region so that compilers can do tricks like computing a
605 * base register of sp + constant and then using a
606 * register-minus-constant addressing mode, which comes up at least
607 * on ARM where the compiler is trying to optimize given the limited
608 * size of immediate offsets available. The maximum such negative
609 * constant on ARM will be -4095, but we use page size (64k) for
610 * good measure and do it on all machines just for uniformity.
612 return ((uintptr_t) 1U << nap->addr_bits) - NACL_MAP_PAGESIZE;
617 * * argc is the length of the argv array
618 * * envv may be NULL (this happens on MacOS/Cocoa and in tests)
619 * * if envv is non-NULL it is 'consistent', null terminated etc.
621 int NaClCreateMainThread(struct NaClApp *nap,
624 char const *const *envv) {
626 * Compute size of string tables for argv and envv
640 retval = 0; /* fail */
642 CHECK(NULL != argv || 0 == argc);
646 char const *const *pp;
647 for (pp = envv; NULL != *pp; ++pp) {
652 argv_len = malloc(argc * sizeof argv_len[0]);
653 envv_len = malloc(envc * sizeof envv_len[0]);
654 if (NULL == argv_len) {
657 if (NULL == envv_len && 0 != envc) {
664 * The following two loops cannot overflow. The reason for this is
665 * that they are counting the number of bytes used to hold the
666 * NUL-terminated strings that comprise the argv and envv tables.
667 * If the entire address space consisted of just those strings, then
668 * the size variable would overflow; however, since there's the code
669 * space required to hold the code below (and we are not targetting
670 * Harvard architecture machines), at least one page holds code, not
671 * data. We are assuming that the caller is non-adversarial and the
672 * code does not look like string data....
674 for (i = 0; i < argc; ++i) {
675 argv_len[i] = strlen(argv[i]) + 1;
678 for (i = 0; i < envc; ++i) {
679 envv_len[i] = strlen(envv[i]) + 1;
684 * NaCl modules are ILP32, so the argv, envv pointers, as well as
685 * the terminating NULL pointers at the end of the argv/envv tables,
686 * are 32-bit values. We also have the auxv to take into account.
688 * The argv and envv pointer tables came from trusted code and is
689 * part of memory. Thus, by the same argument above, adding in
690 * "ptr_tbl_size" cannot possibly overflow the "size" variable since
691 * it is a size_t object. However, the extra pointers for auxv and
692 * the space for argv could cause an overflow. The fact that we
693 * used stack to get here etc means that ptr_tbl_size could not have
696 * NB: the underlying OS would have limited the amount of space used
697 * for argv and envv -- on linux, it is ARG_MAX, or 128KB -- and
698 * hence the overflow check is for obvious auditability rather than
702 if (0 != nap->user_entry_pt) {
705 ptr_tbl_size = (((NACL_STACK_GETS_ARG ? 1 : 0) +
706 (3 + argc + 1 + envc + 1 + auxv_entries * 2)) *
709 if (SIZE_T_MAX - size < ptr_tbl_size) {
711 "NaClCreateMainThread: ptr_tbl_size cause size of"
712 " argv / environment copy to overflow!?!\n");
716 size += ptr_tbl_size;
718 size = (size + NACL_STACK_ALIGN_MASK) & ~NACL_STACK_ALIGN_MASK;
720 if (size > nap->stack_size) {
726 * Write strings and char * arrays to stack.
728 stack_ptr = NaClUserToSysAddrRange(nap, NaClGetInitialStackTop(nap) - size,
730 if (stack_ptr == kNaClBadAddress) {
735 NaClLog(2, "setting stack to : %016"NACL_PRIxPTR"\n", stack_ptr);
737 VCHECK(0 == (stack_ptr & NACL_STACK_ALIGN_MASK),
738 ("stack_ptr not aligned: %016"NACL_PRIxPTR"\n", stack_ptr));
740 p = (uint32_t *) stack_ptr;
741 strp = (char *) stack_ptr + ptr_tbl_size;
744 * For x86-32, we push an initial argument that is the address of
745 * the main argument block. For other machines, this is passed
746 * in a register and that's set in NaClStartThreadInApp.
748 if (NACL_STACK_GETS_ARG) {
749 uint32_t *argloc = p++;
750 *argloc = (uint32_t) NaClSysToUser(nap, (uintptr_t) p);
753 *p++ = 0; /* Cleanup function pointer, always NULL. */
757 for (i = 0; i < argc; ++i) {
758 *p++ = (uint32_t) NaClSysToUser(nap, (uintptr_t) strp);
759 NaClLog(2, "copying arg %d %p -> %p\n",
761 strcpy(strp, argv[i]);
764 *p++ = 0; /* argv[argc] is NULL. */
766 for (i = 0; i < envc; ++i) {
767 *p++ = (uint32_t) NaClSysToUser(nap, (uintptr_t) strp);
768 NaClLog(2, "copying env %d %p -> %p\n",
770 strcpy(strp, envv[i]);
773 *p++ = 0; /* envp[envc] is NULL. */
776 if (0 != nap->user_entry_pt) {
778 *p++ = (uint32_t) nap->user_entry_pt;
783 CHECK((char *) p == (char *) stack_ptr + ptr_tbl_size);
785 /* now actually spawn the thread */
786 NaClXMutexLock(&nap->mu);
788 NaClXMutexUnlock(&nap->mu);
790 NaClVmHoleWaitToStartThread(nap);
793 * For x86, we adjust the stack pointer down to push a dummy return
794 * address. This happens after the stack pointer alignment.
795 * We avoid the otherwise harmless call for the zero case because
796 * _FORTIFY_SOURCE memset can warn about zero-length calls.
798 if (NACL_STACK_PAD_BELOW_ALIGN != 0) {
799 stack_ptr -= NACL_STACK_PAD_BELOW_ALIGN;
800 memset((void *) stack_ptr, 0, NACL_STACK_PAD_BELOW_ALIGN);
803 NaClLog(2, "system stack ptr : %016"NACL_PRIxPTR"\n", stack_ptr);
804 NaClLog(2, " user stack ptr : %016"NACL_PRIxPTR"\n",
805 NaClSysToUserStackAddr(nap, stack_ptr));
807 /* e_entry is user addr */
808 retval = NaClAppThreadSpawn(nap,
809 nap->initial_entry_pt,
810 NaClSysToUserStackAddr(nap, stack_ptr),
811 /* user_tls1= */ (uint32_t) nap->break_addr,
821 int NaClWaitForMainThreadToExit(struct NaClApp *nap) {
822 NaClLog(3, "NaClWaitForMainThreadToExit: taking NaClApp lock\n");
823 NaClXMutexLock(&nap->mu);
824 NaClLog(3, " waiting for exit status\n");
825 while (nap->running) {
826 NaClXCondVarWait(&nap->cv, &nap->mu);
827 NaClLog(3, " wakeup, nap->running %d, nap->exit_status %d\n",
828 nap->running, nap->exit_status);
830 NaClXMutexUnlock(&nap->mu);
832 * Some thread invoked the exit (exit_group) syscall.
835 if (NULL != nap->debug_stub_callbacks) {
836 nap->debug_stub_callbacks->process_exit_hook();
839 return NACL_ABI_WEXITSTATUS(nap->exit_status);
843 * stack_ptr is from syscall, so a 32-bit address.
845 int32_t NaClCreateAdditionalThread(struct NaClApp *nap,
847 uintptr_t sys_stack_ptr,
849 uint32_t user_tls2) {
850 if (!NaClAppThreadSpawn(nap,
852 NaClSysToUserStackAddr(nap, sys_stack_ptr),
856 ("NaClCreateAdditionalThread: could not allocate thread."
857 " Returning EAGAIN per POSIX specs.\n"));
858 return -NACL_ABI_EAGAIN;