am 83b5acf4: am 5d06718c: Merge "Refactor the syscall generation script."

* commit '83b5acf418544394011ee2f29829b5c1791a52eb':
  Refactor the syscall generation script.
This commit is contained in:
Elliott Hughes 2013-10-08 09:58:04 -07:00 committed by Android Git Automerger
commit d2e0b1e777

View File

@ -23,6 +23,7 @@ def make_dir(path):
make_dir(parent) make_dir(parent)
os.mkdir(path) os.mkdir(path)
def create_file(relpath): def create_file(relpath):
dir = os.path.dirname(bionic_temp + relpath) dir = os.path.dirname(bionic_temp + relpath)
make_dir(dir) make_dir(dir)
@ -34,21 +35,85 @@ syscall_stub_header = """/* autogenerated by gensyscalls.py */
#include <linux/err.h> #include <linux/err.h>
#include <machine/asm.h> #include <machine/asm.h>
ENTRY(%(fname)s) ENTRY(%(func)s)
""" """
function_alias = """ function_alias = """
.globl _C_LABEL(%(alias)s) .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 <asm/unistd.h>
.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 assembler templates for each syscall stub
# #
x86_registers = [ "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp" ] x86_registers = [ "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp" ]
x86_call = """ movl $%(idname)s, %%eax x86_call = """\
movl $%(__NR_name)s, %%eax
int $0x80 int $0x80
cmpl $-MAX_ERRNO, %%eax cmpl $-MAX_ERRNO, %%eax
jb 1f jb 1f
@ -60,15 +125,18 @@ x86_call = """ movl $%(idname)s, %%eax
1: 1:
""" """
x86_return = """ ret x86_return = """\
END(%(fname)s) ret
END(%(func)s)
""" """
# #
# x86_64 assembler templates for each syscall stub # x86_64 assembler templates for each syscall stub
# #
x86_64_call = """ movl $%(idname)s, %%eax x86_64_call = """\
movl $%(__NR_name)s, %%eax
syscall syscall
cmpq $-MAX_ERRNO, %%rax cmpq $-MAX_ERRNO, %%rax
jb 1f jb 1f
@ -78,67 +146,9 @@ x86_64_call = """ movl $%(idname)s, %%eax
orq $-1, %%rax orq $-1, %%rax
1: 1:
ret 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 <asm/unistd.h>
.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): def param_uses_64bits(param):
"""Returns True iff a syscall parameter description corresponds """Returns True iff a syscall parameter description corresponds
@ -160,6 +170,7 @@ def param_uses_64bits(param):
# Ok # Ok
return True return True
def count_arm_param_registers(params): def count_arm_param_registers(params):
"""This function is used to count the number of register used """This function is used to count the number of register used
to pass parameters when invoking an ARM system call. to pass parameters when invoking an ARM system call.
@ -184,6 +195,7 @@ def count_arm_param_registers(params):
count += 1 count += 1
return count return count
def count_generic_param_registers(params): def count_generic_param_registers(params):
count = 0 count = 0
for param in params: for param in params:
@ -193,12 +205,14 @@ def count_generic_param_registers(params):
count += 1 count += 1
return count return count
def count_generic_param_registers64(params): def count_generic_param_registers64(params):
count = 0 count = 0
for param in params: for param in params:
count += 1 count += 1
return count return count
# This lets us support regular system calls like __NR_write and also weird # 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. # ones like __ARM_NR_cacheflush, where the NR doesn't come at the start.
def make__NR_name(name): def make__NR_name(name):
@ -207,6 +221,90 @@ def make__NR_name(name):
else: else:
return "__NR_%s" % (name) 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: class State:
def __init__(self): def __init__(self):
self.old_stubs = [] self.old_stubs = []
@ -214,126 +312,34 @@ class State:
self.other_files = [] self.other_files = []
self.syscalls = [] self.syscalls = []
def x86_64_genstub(self, fname, numparams, idname, aliases):
t = { "fname" : fname, "idname" : idname }
result = syscall_stub_header % t def process_file(self, input):
# 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):
parser = SysCallsTxtParser() parser = SysCallsTxtParser()
parser.parse_file(input) parser.parse_file(input)
self.syscalls = parser.syscalls self.syscalls = parser.syscalls
parser = None parser = None
for t in self.syscalls: for syscall in self.syscalls:
syscall_func = t["func"] syscall["__NR_name"] = make__NR_name(syscall["name"])
syscall_aliases = t["aliases"]
syscall_params = t["params"]
syscall_name = t["name"]
__NR_name = make__NR_name(t["name"])
if t.has_key("arm"): if syscall.has_key("arm"):
num_regs = count_arm_param_registers(syscall_params) syscall["asm-arm"] = add_aliases(arm_eabi_genstub(syscall), syscall)
t["asm-arm"] = self.arm_eabi_genstub(syscall_func, num_regs, __NR_name)
if t.has_key("x86"): if syscall.has_key("x86"):
num_regs = count_generic_param_registers(syscall_params) if syscall["socketcall_id"] >= 0:
if t["socketcall_id"] >= 0: syscall["asm-x86"] = add_aliases(x86_genstub_socketcall(syscall), syscall)
t["asm-x86"] = self.x86_genstub_socketcall(syscall_func, __NR_name, t["socketcall_id"])
else: else:
t["asm-x86"] = self.x86_genstub(syscall_func, num_regs, __NR_name) syscall["asm-x86"] = add_aliases(x86_genstub(syscall), syscall)
elif t["socketcall_id"] >= 0: elif syscall["socketcall_id"] >= 0:
E("socketcall_id for dispatch syscalls is only supported for x86 in '%s'" % t) E("socketcall_id for dispatch syscalls is only supported for x86 in '%s'" % t)
return return
if t.has_key("mips"): if syscall.has_key("mips"):
t["asm-mips"] = self.mips_genstub(syscall_func, make__NR_name(syscall_name)) 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 # Scan a Linux kernel asm/unistd.h file containing __NR_* constants
# and write out equivalent SYS_* constants for glibc source compatibility. # and write out equivalent SYS_* constants for glibc source compatibility.
@ -379,22 +385,22 @@ class State:
fp = create_file(path) fp = create_file(path)
fp.write("# Auto-generated by gensyscalls.py. Do not edit.\n") fp.write("# Auto-generated by gensyscalls.py. Do not edit.\n")
fp.write("syscall_src :=\n") fp.write("syscall_src :=\n")
for sc in self.syscalls: for syscall in self.syscalls:
if sc.has_key("asm-%s" % arch): if syscall.has_key("asm-%s" % arch):
fp.write("syscall_src += arch-%s/syscalls/%s.S\n" % (arch, sc["func"])) fp.write("syscall_src += arch-%s/syscalls/%s.S\n" % (arch, syscall["func"]))
fp.close() fp.close()
self.other_files.append(path) self.other_files.append(path)
# Write each syscall stub. # Write each syscall stub.
def gen_syscall_stubs(self): def gen_syscall_stubs(self):
for sc in self.syscalls: for syscall in self.syscalls:
for arch in all_arches: for arch in all_arches:
if sc.has_key("asm-%s" % arch): if syscall.has_key("asm-%s" % arch):
filename = "arch-%s/syscalls/%s.S" % (arch, sc["func"]) filename = "arch-%s/syscalls/%s.S" % (arch, syscall["func"])
D2(">>> generating " + filename) D2(">>> generating " + filename)
fp = create_file(filename) fp = create_file(filename)
fp.write(sc["asm-%s" % arch]) fp.write(syscall["asm-%s" % arch])
fp.close() fp.close()
self.new_stubs.append(filename) self.new_stubs.append(filename)