Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / native_client / src / nonsfi / irt / irt_interfaces.c
1 /*
2  * Copyright (c) 2013 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.
5  */
6
7 #include "native_client/src/nonsfi/irt/irt_interfaces.h"
8
9 #include <assert.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <limits.h>
13 #include <pthread.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/mman.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20
21 #if defined(__linux__)
22 # include <linux/futex.h>
23 # include <sys/syscall.h>
24 #endif
25
26 #include "native_client/src/include/elf32.h"
27 #include "native_client/src/include/elf_auxv.h"
28 #include "native_client/src/include/nacl/nacl_exception.h"
29 #include "native_client/src/include/nacl_macros.h"
30 #include "native_client/src/nonsfi/linux/irt_exception_handling.h"
31 #include "native_client/src/public/irt_core.h"
32 #include "native_client/src/trusted/service_runtime/include/machine/_types.h"
33 #include "native_client/src/trusted/service_runtime/include/sys/mman.h"
34 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
35 #include "native_client/src/trusted/service_runtime/include/sys/time.h"
36 #include "native_client/src/trusted/service_runtime/include/sys/unistd.h"
37 #include "native_client/src/untrusted/irt/irt.h"
38 #include "native_client/src/untrusted/irt/irt_dev.h"
39 #include "native_client/src/untrusted/irt/irt_interfaces.h"
40
41 /*
42  * This is an implementation of NaCl's IRT interfaces that runs
43  * outside of the NaCl sandbox.
44  *
45  * This allows PNaCl to be used as a portability layer without the
46  * SFI-based sandboxing.  PNaCl pexes can be translated to
47  * non-SFI-sandboxed native code and linked against this IRT
48  * implementation.
49  */
50
51
52 #if defined(__ANDROID__) && !defined(FUTEX_PRIVATE_FLAG)
53 /* Android's Linux headers currently don't define this flag. */
54 # define FUTEX_PRIVATE_FLAG 128
55 #endif
56
57 #if defined(__GLIBC__)
58 /*
59  * glibc's headers will define st_atimensec etc. fields, but only if
60  * _POSIX_SOURCE is defined, which disables many other declarations,
61  * such as nanosleep(), getpagesize(), MAP_ANON and clock_gettime().
62  */
63 # define st_atimensec st_atim.tv_nsec
64 # define st_mtimensec st_mtim.tv_nsec
65 # define st_ctimensec st_ctim.tv_nsec
66 #elif defined(__APPLE__)
67 /*
68  * Similarly, Mac OS X's headers will define st_atimensec etc. fields,
69  * but only if _POSIX_SOURCE is defined, which disables declarations
70  * such as _SC_NPROCESSORS_ONLN.
71  */
72 # define st_atimensec st_atimespec.tv_nsec
73 # define st_mtimensec st_mtimespec.tv_nsec
74 # define st_ctimensec st_ctimespec.tv_nsec
75 #endif
76
77 void _user_start(void *info);
78 void _start(void *info);
79
80 /* TODO(mseaborn): Make threads work on Mac OS X. */
81 #if defined(__APPLE__)
82 # define __thread /* nothing */
83 #endif
84 static __thread void *g_tls_value;
85
86 /*
87  * The IRT functions in irt.h are declared as taking "struct timespec"
88  * and "struct timeval" pointers, but these are really "struct
89  * nacl_abi_timespec" and "struct nacl_abi_timeval" pointers in this
90  * unsandboxed context.
91  *
92  * To avoid changing irt.h for now and also avoid casting function
93  * pointers, we use the same type signatures as in irt.h and do the
94  * casting here.
95  */
96 static void convert_from_nacl_timespec(struct timespec *dest,
97                                        const struct timespec *src_nacl) {
98   const struct nacl_abi_timespec *src =
99       (const struct nacl_abi_timespec *) src_nacl;
100   dest->tv_sec = src->tv_sec;
101   dest->tv_nsec = src->tv_nsec;
102 }
103
104 static void convert_to_nacl_timespec(struct timespec *dest_nacl,
105                                      const struct timespec *src) {
106   struct nacl_abi_timespec *dest = (struct nacl_abi_timespec *) dest_nacl;
107   dest->tv_sec = src->tv_sec;
108   dest->tv_nsec = src->tv_nsec;
109 }
110
111 static void convert_to_nacl_timeval(struct timeval *dest_nacl,
112                                     const struct timeval *src) {
113   struct nacl_abi_timeval *dest = (struct nacl_abi_timeval *) dest_nacl;
114   dest->nacl_abi_tv_sec = src->tv_sec;
115   dest->nacl_abi_tv_usec = src->tv_usec;
116 }
117
118 static void convert_to_nacl_stat(struct stat *dest_nacl,
119                                  const struct stat *src) {
120   struct nacl_abi_stat *dest = (struct nacl_abi_stat *) dest_nacl;
121   dest->nacl_abi_st_dev = src->st_dev;
122   dest->nacl_abi_st_ino = src->st_ino;
123   dest->nacl_abi_st_mode = src->st_mode;
124   dest->nacl_abi_st_nlink = src->st_nlink;
125   dest->nacl_abi_st_uid = src->st_uid;
126   dest->nacl_abi_st_gid = src->st_gid;
127   dest->nacl_abi_st_rdev = src->st_rdev;
128   dest->nacl_abi_st_size = src->st_size;
129   dest->nacl_abi_st_blksize = src->st_blksize;
130   dest->nacl_abi_st_blocks = src->st_blocks;
131   dest->nacl_abi_st_atime = src->st_atime;
132   dest->nacl_abi_st_atimensec = src->st_atimensec;
133   dest->nacl_abi_st_mtime = src->st_mtime;
134   dest->nacl_abi_st_mtimensec = src->st_mtimensec;
135   dest->nacl_abi_st_ctime = src->st_ctime;
136   dest->nacl_abi_st_ctimensec = src->st_ctimensec;
137 }
138
139 static void copy_flag(int *dest, int src, int new_flag, int old_flag) {
140   if ((src & old_flag) != 0)
141     *dest |= new_flag;
142 }
143
144 /* Returns whether the conversion was successful. */
145 static int convert_from_nacl_mmap_prot(int *prot, int prot_nacl) {
146   if ((prot_nacl & ~NACL_ABI_PROT_MASK) != 0)
147     return 0;
148   *prot = 0;
149   copy_flag(prot, prot_nacl, PROT_READ, NACL_ABI_PROT_READ);
150   copy_flag(prot, prot_nacl, PROT_WRITE, NACL_ABI_PROT_WRITE);
151   copy_flag(prot, prot_nacl, PROT_EXEC, NACL_ABI_PROT_EXEC);
152   return 1;
153 }
154
155 /* Returns whether the conversion was successful. */
156 static int convert_from_nacl_mmap_flags(int *flags, int flags_nacl) {
157   int allowed = NACL_ABI_MAP_SHARED |
158                 NACL_ABI_MAP_PRIVATE |
159                 NACL_ABI_MAP_FIXED |
160                 NACL_ABI_MAP_ANON;
161   if ((flags_nacl & ~allowed) != 0)
162     return 0;
163   *flags = 0;
164   copy_flag(flags, flags_nacl, MAP_SHARED, NACL_ABI_MAP_SHARED);
165   copy_flag(flags, flags_nacl, MAP_PRIVATE, NACL_ABI_MAP_PRIVATE);
166   copy_flag(flags, flags_nacl, MAP_FIXED, NACL_ABI_MAP_FIXED);
167   copy_flag(flags, flags_nacl, MAP_ANON, NACL_ABI_MAP_ANON);
168   return 1;
169 }
170
171 static int check_error(int result) {
172   if (result != 0) {
173     /*
174      * Check that we really have an error and don't indicate success
175      * mistakenly.
176      */
177     assert(errno != 0);
178     return errno;
179   }
180   return 0;
181 }
182
183 static int irt_close(int fd) {
184   return check_error(close(fd));
185 }
186
187 static int irt_dup(int fd, int *new_fd) {
188   int result = dup(fd);
189   if (result < 0)
190     return errno;
191   *new_fd = result;
192   return 0;
193 }
194
195 static int irt_dup2(int fd, int new_fd) {
196   int result = dup2(fd, new_fd);
197   if (result < 0)
198     return errno;
199   assert(result == new_fd);
200   return 0;
201 }
202
203 static int irt_read(int fd, void *buf, size_t count, size_t *nread) {
204   int result = read(fd, buf, count);
205   if (result < 0)
206     return errno;
207   *nread = result;
208   return 0;
209 }
210
211 static int irt_write(int fd, const void *buf, size_t count, size_t *nwrote) {
212   int result = write(fd, buf, count);
213   if (result < 0)
214     return errno;
215   *nwrote = result;
216   return 0;
217 }
218
219 static int irt_seek(int fd, nacl_abi_off_t offset, int whence,
220                     nacl_abi_off_t *new_offset) {
221   off_t result = lseek(fd, offset, whence);
222   if (result < 0)
223     return errno;
224   *new_offset = result;
225   return 0;
226 }
227
228 static int irt_fstat(int fd, struct stat *st_nacl) {
229   struct stat st;
230   if (fstat(fd, &st) != 0)
231     return errno;
232   convert_to_nacl_stat(st_nacl, &st);
233   return 0;
234 }
235
236 static void irt_exit(int status) {
237   _exit(status);
238 }
239
240 static int irt_clock_func(clock_t *ticks) {
241   clock_t result = clock();
242   if (result == (clock_t) -1)
243     return errno;
244   *ticks = result;
245   return 0;
246 }
247
248 static int irt_gettod(struct timeval *time_nacl) {
249   struct timeval time;
250   int result = check_error(gettimeofday(&time, NULL));
251   convert_to_nacl_timeval(time_nacl, &time);
252   return result;
253 }
254
255 static int irt_sched_yield(void) {
256   return check_error(sched_yield());
257 }
258
259 static int irt_nanosleep(const struct timespec *requested_nacl,
260                          struct timespec *remaining_nacl) {
261   struct timespec requested;
262   struct timespec remaining;
263   convert_from_nacl_timespec(&requested, requested_nacl);
264   int result = check_error(nanosleep(&requested, &remaining));
265   if (remaining_nacl != NULL)
266     convert_to_nacl_timespec(remaining_nacl, &remaining);
267   return result;
268 }
269
270 static int irt_sysconf(int name, int *value) {
271   switch (name) {
272     case NACL_ABI__SC_PAGESIZE:
273       /*
274        * For now, return the host's page size (typically 4k) rather
275        * than 64k (NaCl's usual page size), which pexes will usually
276        * be tested with.  We could change this to 64k, but then the
277        * mmap() we define here should round up requested sizes to
278        * multiples of 64k.
279        */
280       *value = getpagesize();
281       return 0;
282     case NACL_ABI__SC_NPROCESSORS_ONLN: {
283       int result = sysconf(_SC_NPROCESSORS_ONLN);
284       if (result == 0)
285         return errno;
286       *value = result;
287       return 0;
288     }
289     default:
290       return EINVAL;
291   }
292 }
293
294 static int irt_mmap(void **addr, size_t len, int prot, int flags,
295                     int fd, nacl_irt_off_t off) {
296   int host_prot;
297   int host_flags;
298   if (!convert_from_nacl_mmap_prot(&host_prot, prot) ||
299       !convert_from_nacl_mmap_flags(&host_flags, flags)) {
300     return EINVAL;
301   }
302   void *result = mmap(*addr, len, host_prot, host_flags, fd, off);
303   if (result == MAP_FAILED)
304     return errno;
305   *addr = result;
306   return 0;
307 }
308
309 static int irt_munmap(void *addr, size_t len) {
310   return check_error(munmap(addr, len));
311 }
312
313 static int irt_mprotect(void *addr, size_t len, int prot) {
314   int host_prot;
315   if (!convert_from_nacl_mmap_prot(&host_prot, prot)) {
316     return EINVAL;
317   }
318   return check_error(mprotect(addr, len, host_prot));
319 }
320
321 static int tls_init(void *ptr) {
322   g_tls_value = ptr;
323   return 0;
324 }
325
326 static void *tls_get(void) {
327   return g_tls_value;
328 }
329
330 /* For newlib based nonsfi_loader, we use the one defined in pnacl_irt.c. */
331 #if !defined(__native_client__)
332 void *__nacl_read_tp(void) {
333   return g_tls_value;
334 }
335 #endif
336
337 struct thread_args {
338   void (*start_func)(void);
339   void *thread_ptr;
340 };
341
342 static void *start_thread(void *arg) {
343   struct thread_args args = *(struct thread_args *) arg;
344   free(arg);
345   g_tls_value = args.thread_ptr;
346   args.start_func();
347   abort();
348 }
349
350 static int thread_create(void (*start_func)(void), void *stack,
351                          void *thread_ptr) {
352   /*
353    * For now, we ignore the stack that user code provides and just use
354    * the stack that the host libpthread allocates.
355    */
356   pthread_attr_t attr;
357   int error = pthread_attr_init(&attr);
358   if (error != 0)
359     return error;
360   error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
361   if (error != 0)
362     return error;
363   struct thread_args *args = malloc(sizeof(struct thread_args));
364   if (args == NULL) {
365     error = ENOMEM;
366     goto cleanup;
367   }
368   args->start_func = start_func;
369   args->thread_ptr = thread_ptr;
370   pthread_t tid;
371   error = pthread_create(&tid, &attr, start_thread, args);
372   if (error != 0)
373     free(args);
374  cleanup:
375   pthread_attr_destroy(&attr);
376   return error;
377 }
378
379 static void thread_exit(int32_t *stack_flag) {
380   *stack_flag = 0;  /* Indicate that the user code's stack can be freed. */
381   pthread_exit(NULL);
382 }
383
384 static int thread_nice(const int nice) {
385   return 0;
386 }
387
388 /*
389  * Mac OS X does not provide futexes or clock_gettime()/getres() natively.
390  * TODO(mseaborn):  Make threads and clock_gettime() work on Mac OS X.
391  */
392 #if defined(__linux__)
393 static int futex_wait_abs(volatile int *addr, int value,
394                           const struct timespec *abstime_nacl) {
395   struct timespec reltime;
396   struct timespec *reltime_ptr = NULL;
397   if (abstime_nacl != NULL) {
398     struct timespec time_now;
399     if (clock_gettime(CLOCK_REALTIME, &time_now) != 0)
400       return errno;
401
402     /* Convert the absolute time to a relative time. */
403     const struct nacl_abi_timespec *abstime =
404         (const struct nacl_abi_timespec *) abstime_nacl;
405     reltime.tv_sec = abstime->tv_sec - time_now.tv_sec;
406     reltime.tv_nsec = abstime->tv_nsec - time_now.tv_nsec;
407     if (reltime.tv_nsec < 0) {
408       reltime.tv_sec -= 1;
409       reltime.tv_nsec += 1000000000;
410     }
411     /*
412      * Linux's FUTEX_WAIT returns EINVAL if given a negative relative
413      * time.  But an absolute time that's in the past is a valid
414      * argument, for which we need to return ETIMEDOUT instead.
415      */
416     if (reltime.tv_sec < 0)
417       return ETIMEDOUT;
418     reltime_ptr = &reltime;
419   }
420   return check_error(syscall(__NR_futex, addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG,
421                              value, reltime_ptr, 0, 0));
422 }
423
424 static int futex_wake(volatile int *addr, int nwake, int *count) {
425   int result = syscall(__NR_futex, addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
426                        nwake, 0, 0, 0);
427   if (result < 0)
428     return errno;
429   *count = result;
430   return 0;
431 }
432 #endif
433
434 #if defined(__linux__) || defined(__native_client__)
435 static int irt_clock_getres(nacl_irt_clockid_t clk_id,
436                             struct timespec *time_nacl) {
437   struct timespec time;
438   int result = check_error(clock_getres(clk_id, &time));
439   /*
440    * The timespec pointer is allowed to be NULL for clock_getres() though
441    * not for clock_gettime().
442    */
443   if (time_nacl != NULL)
444     convert_to_nacl_timespec(time_nacl, &time);
445   return result;
446 }
447
448 static int irt_clock_gettime(nacl_irt_clockid_t clk_id,
449                              struct timespec *time_nacl) {
450   struct timespec time;
451   int result = check_error(clock_gettime(clk_id, &time));
452   convert_to_nacl_timespec(time_nacl, &time);
453   return result;
454 }
455 #endif
456
457 static int irt_open(const char *pathname, int flags, mode_t mode, int *new_fd) {
458   int fd = open(pathname, flags, mode);
459   if (fd < 0)
460     return errno;
461   *new_fd = fd;
462   return 0;
463 }
464
465 static int irt_stat(const char *pathname, struct stat *stat_info_nacl) {
466   struct stat stat_info;
467   if (stat(pathname, &stat_info) != 0)
468     return errno;
469   convert_to_nacl_stat(stat_info_nacl, &stat_info);
470   return 0;
471 }
472
473 static int irt_lstat(const char *pathname, struct stat *stat_info_nacl) {
474   struct stat stat_info;
475   if (lstat(pathname, &stat_info) != 0)
476     return errno;
477   convert_to_nacl_stat(stat_info_nacl, &stat_info);
478   return 0;
479 }
480
481 static int irt_mkdir(const char *pathname, mode_t mode) {
482   return check_error(mkdir(pathname, mode));
483 }
484
485 static int irt_rmdir(const char *pathname) {
486   return check_error(rmdir(pathname));
487 }
488
489 static int irt_chdir(const char *pathname) {
490   return check_error(chdir(pathname));
491 }
492
493 static int irt_getcwd(char *pathname, size_t len) {
494   if (getcwd(pathname, len) == NULL)
495     return errno;
496   return 0;
497 }
498
499 static int irt_unlink(const char *pathname) {
500   return check_error(unlink(pathname));
501 }
502
503 static int irt_truncate(const char *pathname, nacl_irt_off_t length) {
504   return check_error(truncate(pathname, length));
505 }
506
507 static int irt_link(const char *oldpath, const char *newpath) {
508   return check_error(link(oldpath, newpath));
509 }
510
511 static int irt_rename(const char *oldpath, const char *newpath) {
512   return check_error(rename(oldpath, newpath));
513 }
514
515 static int irt_symlink(const char *oldpath, const char *newpath) {
516   return check_error(symlink(oldpath, newpath));
517 }
518
519 static int irt_chmod(const char *pathname, mode_t mode) {
520   return check_error(chmod(pathname, mode));
521 }
522
523 static int irt_access(const char *pathname, int mode) {
524   return check_error(access(pathname, mode));
525 }
526
527 static int irt_readlink(const char *path, char *buf, size_t count,
528                         size_t *nread) {
529   ssize_t result = readlink(path, buf, count);
530   if (result < 0)
531     return errno;
532   *nread = result;
533   return 0;
534 }
535
536 static int irt_getpid(int *pid) {
537   *pid = getpid();
538   return 0;
539 }
540
541 static void irt_stub_func(const char *name) {
542   fprintf(stderr, "Error: Unimplemented IRT function: %s\n", name);
543   abort();
544 }
545
546 #define DEFINE_STUB(name) \
547     static void irt_stub_##name() { irt_stub_func(#name); }
548 #define USE_STUB(s, name) (__typeof__(s.name)) irt_stub_##name
549
550 const struct nacl_irt_basic nacl_irt_basic = {
551   irt_exit,
552   irt_gettod,
553   irt_clock_func,
554   irt_nanosleep,
555   irt_sched_yield,
556   irt_sysconf,
557 };
558
559 DEFINE_STUB(getdents)
560 const struct nacl_irt_fdio nacl_irt_fdio = {
561   irt_close,
562   irt_dup,
563   irt_dup2,
564   irt_read,
565   irt_write,
566   irt_seek,
567   irt_fstat,
568   USE_STUB(nacl_irt_fdio, getdents),
569 };
570
571 const struct nacl_irt_memory nacl_irt_memory = {
572   irt_mmap,
573   irt_munmap,
574   irt_mprotect,
575 };
576
577 const struct nacl_irt_tls nacl_irt_tls = {
578   tls_init,
579   tls_get,
580 };
581
582 const struct nacl_irt_thread nacl_irt_thread = {
583   thread_create,
584   thread_exit,
585   thread_nice,
586 };
587
588 #if defined(__linux__)
589 const struct nacl_irt_futex nacl_irt_futex = {
590   futex_wait_abs,
591   futex_wake,
592 };
593 #elif !defined(__native_client__)
594 DEFINE_STUB(futex_wait_abs)
595 DEFINE_STUB(futex_wake)
596 const struct nacl_irt_futex nacl_irt_futex = {
597   USE_STUB(nacl_irt_futex, futex_wait_abs),
598   USE_STUB(nacl_irt_futex, futex_wake),
599 };
600 #endif
601
602 #if defined(__linux__) || defined(__native_client__)
603 const struct nacl_irt_clock nacl_irt_clock = {
604   irt_clock_getres,
605   irt_clock_gettime,
606 };
607 #endif
608
609 DEFINE_STUB(utimes)
610 const struct nacl_irt_dev_filename nacl_irt_dev_filename = {
611   irt_open,
612   irt_stat,
613   irt_mkdir,
614   irt_rmdir,
615   irt_chdir,
616   irt_getcwd,
617   irt_unlink,
618   irt_truncate,
619   irt_lstat,
620   irt_link,
621   irt_rename,
622   irt_symlink,
623   irt_chmod,
624   irt_access,
625   irt_readlink,
626   USE_STUB(nacl_irt_dev_filename, utimes),
627 };
628
629 const struct nacl_irt_dev_getpid nacl_irt_dev_getpid = {
630   irt_getpid,
631 };
632
633 /*
634  * The following condition is true when building for Non-SFI Mode,
635  * when we're calling Linux syscalls directly.  (Counter-intuitively,
636  * "__linux__" is not #defined in this case.)
637  */
638 #if defined(__native_client__)
639 const struct nacl_irt_exception_handling nacl_irt_exception_handling = {
640   nacl_exception_get_and_set_handler,
641   nacl_exception_set_stack,
642   nacl_exception_clear_flag,
643 };
644 #endif
645
646 static const struct nacl_irt_interface irt_interfaces[] = {
647   { NACL_IRT_BASIC_v0_1, &nacl_irt_basic, sizeof(nacl_irt_basic), NULL },
648   { NACL_IRT_FDIO_v0_1, &nacl_irt_fdio, sizeof(nacl_irt_fdio), NULL },
649   { NACL_IRT_MEMORY_v0_3, &nacl_irt_memory, sizeof(nacl_irt_memory), NULL },
650   { NACL_IRT_TLS_v0_1, &nacl_irt_tls, sizeof(nacl_irt_tls), NULL },
651   { NACL_IRT_THREAD_v0_1, &nacl_irt_thread, sizeof(nacl_irt_thread), NULL },
652   { NACL_IRT_FUTEX_v0_1, &nacl_irt_futex, sizeof(nacl_irt_futex), NULL },
653 #if defined(__linux__) || defined(__native_client__)
654   { NACL_IRT_CLOCK_v0_1, &nacl_irt_clock, sizeof(nacl_irt_clock), NULL },
655 #endif
656   { NACL_IRT_DEV_FILENAME_v0_3, &nacl_irt_dev_filename,
657     sizeof(nacl_irt_dev_filename), NULL },
658   { NACL_IRT_DEV_GETPID_v0_1, &nacl_irt_dev_getpid,
659     sizeof(nacl_irt_dev_getpid), NULL },
660 #if defined(__native_client__)
661   { NACL_IRT_EXCEPTION_HANDLING_v0_1, &nacl_irt_exception_handling,
662     sizeof(nacl_irt_exception_handling), NULL},
663 #endif
664 };
665
666 size_t nacl_irt_query_core(const char *interface_ident,
667                            void *table, size_t tablesize) {
668   return nacl_irt_query_list(interface_ident, table, tablesize,
669                              irt_interfaces, sizeof(irt_interfaces));
670 }
671
672 int nacl_irt_nonsfi_entry(int argc, char **argv, char **environ,
673                           nacl_entry_func_t entry_func) {
674   /* Find size of environ array. */
675   size_t env_count = 0;
676   while (environ[env_count] != NULL)
677     env_count++;
678
679   size_t count =
680       1  /* cleanup_func pointer */
681       + 2  /* envc and argc counts */
682       + argc + 1  /* argv array, with terminator */
683       + env_count + 1  /* environ array, with terminator */
684       + 4;  /* auxv: 2 entries, one of them the terminator */
685   uintptr_t *data = malloc(count * sizeof(uintptr_t));
686   if (data == NULL) {
687     fprintf(stderr, "Failed to allocate argv/env/auxv array\n");
688     return 1;
689   }
690   size_t pos = 0;
691   data[pos++] = 0;  /* cleanup_func pointer */
692   data[pos++] = env_count;
693   data[pos++] = argc;
694   /* Copy arrays, with terminators. */
695   size_t i;
696   for (i = 0; i < (size_t) argc; i++)
697     data[pos++] = (uintptr_t) argv[i];
698   data[pos++] = 0;
699   for (i = 0; i < env_count; i++)
700     data[pos++] = (uintptr_t) environ[i];
701   data[pos++] = 0;
702   /* auxv[0] */
703   data[pos++] = AT_SYSINFO;
704   data[pos++] = (uintptr_t) nacl_irt_query_core;
705   /* auxv[1] */
706   data[pos++] = 0;
707   data[pos++] = 0;
708   assert(pos == count);
709
710   entry_func(data);
711   return 1;
712 }
713
714 #if defined(DEFINE_MAIN)
715 int main(int argc, char **argv, char **environ) {
716   /*
717    * On Linux, we rename _start() to _user_start() to avoid a clash
718    * with the "_start" routine in the host toolchain.  On Mac OS X,
719    * lacking objcopy, doing the symbol renaming is trickier, but also
720    * unnecessary, because the host toolchain doesn't have a "_start"
721    * routine.
722    */
723   nacl_entry_func_t entry_func =
724 #if defined(__APPLE__)
725     _start;
726 #else
727     _user_start;
728 #endif
729
730   return nacl_irt_nonsfi_entry(argc, argv, environ, entry_func);
731 }
732 #endif