diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py index 386a8db92..d31af9d83 100755 --- a/libc/tools/gensyscalls.py +++ b/libc/tools/gensyscalls.py @@ -23,6 +23,7 @@ def make_dir(path): make_dir(parent) os.mkdir(path) + def create_file(relpath): dir = os.path.dirname(bionic_temp + relpath) make_dir(dir) @@ -34,21 +35,85 @@ syscall_stub_header = """/* autogenerated by gensyscalls.py */ #include #include -ENTRY(%(fname)s) +ENTRY(%(func)s) """ + function_alias = """ .globl _C_LABEL(%(alias)s) - .equ _C_LABEL(%(alias)s), _C_LABEL(%(fname)s) + .equ _C_LABEL(%(alias)s), _C_LABEL(%(func)s) """ + +# +# ARM assembler templates for each syscall stub +# + +arm_eabi_call_default = syscall_stub_header + """\ + mov ip, r7 + ldr r7, =%(__NR_name)s + swi #0 + mov r7, ip + cmn r0, #(MAX_ERRNO + 1) + bxls lr + neg r0, r0 + b __set_errno +END(%(func)s) +""" + +arm_eabi_call_long = syscall_stub_header + """\ + mov ip, sp + .save {r4, r5, r6, r7} + stmfd sp!, {r4, r5, r6, r7} + ldmfd ip, {r4, r5, r6} + ldr r7, =%(__NR_name)s + swi #0 + ldmfd sp!, {r4, r5, r6, r7} + cmn r0, #(MAX_ERRNO + 1) + bxls lr + neg r0, r0 + b __set_errno +END(%(func)s) +""" + + +# +# MIPS assembler templates for each syscall stub +# + +mips_call = """/* autogenerated by gensyscalls.py */ +#include + .text + .globl %(func)s + .align 4 + .ent %(func)s + +%(func)s: + .set noreorder + .cpload $t9 + li $v0, %(__NR_name)s + syscall + bnez $a3, 1f + move $a0, $v0 + j $ra + nop +1: + la $t9,__set_errno + j $t9 + nop + .set reorder + .end %(func)s +""" + + # # x86 assembler templates for each syscall stub # x86_registers = [ "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp" ] -x86_call = """ movl $%(idname)s, %%eax +x86_call = """\ + movl $%(__NR_name)s, %%eax int $0x80 cmpl $-MAX_ERRNO, %%eax jb 1f @@ -60,15 +125,18 @@ x86_call = """ movl $%(idname)s, %%eax 1: """ -x86_return = """ ret -END(%(fname)s) +x86_return = """\ + ret +END(%(func)s) """ + # # x86_64 assembler templates for each syscall stub # -x86_64_call = """ movl $%(idname)s, %%eax +x86_64_call = """\ + movl $%(__NR_name)s, %%eax syscall cmpq $-MAX_ERRNO, %%rax jb 1f @@ -78,67 +146,9 @@ x86_64_call = """ movl $%(idname)s, %%eax orq $-1, %%rax 1: ret -END(%(fname)s) +END(%(func)s) """ -# -# ARM assembler templates for each syscall stub -# - -arm_eabi_call_default = syscall_stub_header + """\ - mov ip, r7 - ldr r7, =%(idname)s - swi #0 - mov r7, ip - cmn r0, #(MAX_ERRNO + 1) - bxls lr - neg r0, r0 - b __set_errno -END(%(fname)s) -""" - -arm_eabi_call_long = syscall_stub_header + """\ - mov ip, sp - .save {r4, r5, r6, r7} - stmfd sp!, {r4, r5, r6, r7} - ldmfd ip, {r4, r5, r6} - ldr r7, =%(idname)s - swi #0 - ldmfd sp!, {r4, r5, r6, r7} - cmn r0, #(MAX_ERRNO + 1) - bxls lr - neg r0, r0 - b __set_errno -END(%(fname)s) -""" - -# -# mips assembler templates for each syscall stub -# - -mips_call = """/* autogenerated by gensyscalls.py */ -#include - .text - .globl %(fname)s - .align 4 - .ent %(fname)s - -%(fname)s: - .set noreorder - .cpload $t9 - li $v0, %(idname)s - syscall - bnez $a3, 1f - move $a0, $v0 - j $ra - nop -1: - la $t9,__set_errno - j $t9 - nop - .set reorder - .end %(fname)s -""" def param_uses_64bits(param): """Returns True iff a syscall parameter description corresponds @@ -160,6 +170,7 @@ def param_uses_64bits(param): # Ok return True + def count_arm_param_registers(params): """This function is used to count the number of register used to pass parameters when invoking an ARM system call. @@ -184,6 +195,7 @@ def count_arm_param_registers(params): count += 1 return count + def count_generic_param_registers(params): count = 0 for param in params: @@ -193,12 +205,14 @@ def count_generic_param_registers(params): count += 1 return count + def count_generic_param_registers64(params): count = 0 for param in params: count += 1 return count + # This lets us support regular system calls like __NR_write and also weird # ones like __ARM_NR_cacheflush, where the NR doesn't come at the start. def make__NR_name(name): @@ -207,6 +221,90 @@ def make__NR_name(name): else: return "__NR_%s" % (name) + +def add_aliases(stub, syscall): + aliases = syscall["aliases"] + for alias in aliases: + stub += function_alias % { "func" : syscall["func"], "alias" : alias } + return stub + + +def arm_eabi_genstub(syscall): + num_regs = count_arm_param_registers(syscall["params"]) + if num_regs > 4: + return arm_eabi_call_long % syscall + return arm_eabi_call_default % syscall + + +def mips_genstub(syscall): + return mips_call % syscall + + +def x86_genstub(syscall): + result = syscall_stub_header % syscall + stack_bias = 4 + + numparams = count_generic_param_registers(syscall["params"]) + for r in range(numparams): + result += " pushl " + x86_registers[r] + "\n" + stack_bias += 4 + + for r in range(numparams): + result += " mov %d(%%esp), %s" % (stack_bias+r*4, x86_registers[r]) + "\n" + + result += x86_call % syscall + + for r in range(numparams): + result += " popl " + x86_registers[numparams-r-1] + "\n" + + result += x86_return % syscall + return result + +def x86_genstub_socketcall(syscall): + # %ebx <--- Argument 1 - The call id of the needed vectored + # syscall (socket, bind, recv, etc) + # %ecx <--- Argument 2 - Pointer to the rest of the arguments + # from the original function called (socket()) + + result = syscall_stub_header % syscall + stack_bias = 4 + + # save the regs we need + result += " pushl %ebx" + "\n" + stack_bias += 4 + result += " pushl %ecx" + "\n" + stack_bias += 4 + + # set the call id (%ebx) + result += " mov $%d, %%ebx" % syscall["socketcall_id"] + "\n" + + # set the pointer to the rest of the args into %ecx + result += " mov %esp, %ecx" + "\n" + result += " addl $%d, %%ecx" % (stack_bias) + "\n" + + # now do the syscall code itself + result += x86_call % syscall + + # now restore the saved regs + result += " popl %ecx" + "\n" + result += " popl %ebx" + "\n" + + # epilog + result += x86_return % syscall + return result + + +def x86_64_genstub(syscall): + result = syscall_stub_header % syscall + num_regs = count_generic_param_registers64(syscall["params"]) + if (num_regs > 3): + # rcx is used as 4th argument. Kernel wants it at r10. + result += " movq %rcx, %r10\n" + + result += x86_64_call % syscall + return result + + class State: def __init__(self): self.old_stubs = [] @@ -214,126 +312,34 @@ class State: self.other_files = [] self.syscalls = [] - def x86_64_genstub(self, fname, numparams, idname, aliases): - t = { "fname" : fname, "idname" : idname } - result = syscall_stub_header % t - # rcx is used as 4th argument. Kernel wants it at r10. - if (numparams > 3): - result += " movq %rcx, %r10\n" - - result += x86_64_call % t - for alias in aliases: - t = { "fname" : fname, "alias" : alias } - result += function_alias % t - - return result - - def x86_genstub(self, fname, numparams, idname): - t = { "fname" : fname, - "idname" : idname } - - result = syscall_stub_header % t - stack_bias = 4 - for r in range(numparams): - result += " pushl " + x86_registers[r] + "\n" - stack_bias += 4 - - for r in range(numparams): - result += " mov %d(%%esp), %s" % (stack_bias+r*4, x86_registers[r]) + "\n" - - result += x86_call % t - - for r in range(numparams): - result += " popl " + x86_registers[numparams-r-1] + "\n" - - result += x86_return % t - return result - - def x86_genstub_socketcall(self, fname, idname, socketcall_id): - # %ebx <--- Argument 1 - The call id of the needed vectored - # syscall (socket, bind, recv, etc) - # %ecx <--- Argument 2 - Pointer to the rest of the arguments - # from the original function called (socket()) - t = { "fname" : fname, - "idname" : idname } - - result = syscall_stub_header % t - stack_bias = 4 - - # save the regs we need - result += " pushl %ebx" + "\n" - stack_bias += 4 - result += " pushl %ecx" + "\n" - stack_bias += 4 - - # set the call id (%ebx) - result += " mov $%d, %%ebx" % (socketcall_id) + "\n" - - # set the pointer to the rest of the args into %ecx - result += " mov %esp, %ecx" + "\n" - result += " addl $%d, %%ecx" % (stack_bias) + "\n" - - # now do the syscall code itself - result += x86_call % t - - # now restore the saved regs - result += " popl %ecx" + "\n" - result += " popl %ebx" + "\n" - - # epilog - result += x86_return % t - return result - - - def arm_eabi_genstub(self,fname, flags, idname): - t = { "fname" : fname, - "idname" : idname } - if flags: - numargs = int(flags) - if numargs > 4: - return arm_eabi_call_long % t - return arm_eabi_call_default % t - - - def mips_genstub(self,fname, idname): - t = { "fname" : fname, - "idname" : idname } - return mips_call % t - - def process_file(self,input): + def process_file(self, input): parser = SysCallsTxtParser() parser.parse_file(input) self.syscalls = parser.syscalls parser = None - for t in self.syscalls: - syscall_func = t["func"] - syscall_aliases = t["aliases"] - syscall_params = t["params"] - syscall_name = t["name"] - __NR_name = make__NR_name(t["name"]) + for syscall in self.syscalls: + syscall["__NR_name"] = make__NR_name(syscall["name"]) - if t.has_key("arm"): - num_regs = count_arm_param_registers(syscall_params) - t["asm-arm"] = self.arm_eabi_genstub(syscall_func, num_regs, __NR_name) + if syscall.has_key("arm"): + syscall["asm-arm"] = add_aliases(arm_eabi_genstub(syscall), syscall) - if t.has_key("x86"): - num_regs = count_generic_param_registers(syscall_params) - if t["socketcall_id"] >= 0: - t["asm-x86"] = self.x86_genstub_socketcall(syscall_func, __NR_name, t["socketcall_id"]) + if syscall.has_key("x86"): + if syscall["socketcall_id"] >= 0: + syscall["asm-x86"] = add_aliases(x86_genstub_socketcall(syscall), syscall) else: - t["asm-x86"] = self.x86_genstub(syscall_func, num_regs, __NR_name) - elif t["socketcall_id"] >= 0: + syscall["asm-x86"] = add_aliases(x86_genstub(syscall), syscall) + elif syscall["socketcall_id"] >= 0: E("socketcall_id for dispatch syscalls is only supported for x86 in '%s'" % t) return - if t.has_key("mips"): - t["asm-mips"] = self.mips_genstub(syscall_func, make__NR_name(syscall_name)) + if syscall.has_key("mips"): + syscall["asm-mips"] = add_aliases(mips_genstub(syscall), syscall) + + if syscall.has_key("x86_64"): + syscall["asm-x86_64"] = add_aliases(x86_64_genstub(syscall), syscall) - if t.has_key("x86_64"): - num_regs = count_generic_param_registers64(syscall_params) - t["asm-x86_64"] = self.x86_64_genstub(syscall_func, num_regs, __NR_name, syscall_aliases) # Scan a Linux kernel asm/unistd.h file containing __NR_* constants # and write out equivalent SYS_* constants for glibc source compatibility. @@ -379,22 +385,22 @@ class State: fp = create_file(path) fp.write("# Auto-generated by gensyscalls.py. Do not edit.\n") fp.write("syscall_src :=\n") - for sc in self.syscalls: - if sc.has_key("asm-%s" % arch): - fp.write("syscall_src += arch-%s/syscalls/%s.S\n" % (arch, sc["func"])) + for syscall in self.syscalls: + if syscall.has_key("asm-%s" % arch): + fp.write("syscall_src += arch-%s/syscalls/%s.S\n" % (arch, syscall["func"])) fp.close() self.other_files.append(path) # Write each syscall stub. def gen_syscall_stubs(self): - for sc in self.syscalls: + for syscall in self.syscalls: for arch in all_arches: - if sc.has_key("asm-%s" % arch): - filename = "arch-%s/syscalls/%s.S" % (arch, sc["func"]) + if syscall.has_key("asm-%s" % arch): + filename = "arch-%s/syscalls/%s.S" % (arch, syscall["func"]) D2(">>> generating " + filename) fp = create_file(filename) - fp.write(sc["asm-%s" % arch]) + fp.write(syscall["asm-%s" % arch]) fp.close() self.new_stubs.append(filename)