Search code examples
macossystem-callsdarwinxnu

What is wrong with mmap system-call on Mac OS X?


I am trying to write a simple application on Mac OS X using only syscalls, no standard library.

main.c

#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define MAP_ANONYMOUS 0x20
#define MAP_PRIVATE 0x02

#define PAGE_SIZE 4096

#define NULL 0

#define STDOUT 1

#define SYSCALL_BASE 0x2000000
#define SYSCALL_GET(num) SYSCALL_BASE + num

long long syscall(long long arg1, long long arg2, long long arg3, long long arg4, long long arg5, long long arg6, long long cn);

void exit(long long status) {
  syscall(status, 0, 0, 0, 0, 0, SYSCALL_GET(1));
}

long long write(long long fd, char *buf, long long len) {
  return syscall(fd, buf, len, 0, 0, 0, SYSCALL_GET(4));
}

void *mmap(void *addr, long long length, long long prot, long long flags, long long fd, long long offset) {
  return syscall(addr, length, prot, flags, fd, offset, SYSCALL_GET(197));
} 

long long munmap(void *addr, long long length) {
  return syscall(addr, length, 0, 0, 0, 0, SYSCALL_GET(73));
}

int strlen(char *s) {
  int len = 0;
  while (*(s++) != '\0') {
    len++;
  }
  return len;
}

int putchar(char c) {
  return write(STDOUT, &c, 1);
}

int main(int argc, char *argv[]) {
  if (argc <= 1) {
    return 0;
  }

  int *lengths = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);

  for (int i = 1; i < argc; i++) {
    lengths[i] = strlen(argv[i]);
  }

  for (int i = 1; i < argc; i++) {
    write(STDOUT, argv[i], lengths[i]);
    putchar(' ');
  }

  putchar('\n');

  munmap(lengths, PAGE_SIZE);
  return 0;
}

start.s

.global start
.global _syscall

.text
start:
popq %rdi
movq %rsp, %rsi
andq $0xfffffffffffffff0, %rsp
call _main
movq %rax, %rdi
call _exit

_syscall:
movq %rcx, %r10
movq 8(%rsp), %rax
pushq %rbx # alignment
syscall
popq %rbx
retq

As you can see, the application basically reflects simple echo. When I run the program with no arguments, it successfully finishes, so I assume exit call works. But when I run it with any argument, it crashes with Segmentation fault: 11. As far as I understand it now, when mmap is called, kernel returns strange value: 9. I assume that 9 is not a proper address, but I cannot understand my mistake, because according to documentations, all the values passed to syscall are correct. Syscall numbers are taken from here.


Solution

  • I would like to know too.

    I think apple uses MAP_ANON, which is a different number. Try

    #define MAP_ANON    0x1000
    

    https://github.com/nneonneo/osx-10.9-opensource/blob/master/xnu-2422.1.72/bsd/sys/mman.h#L150