Bug 1561088 - emit unwind information for libffi aarch64/win assembly; r=dmajor,gsvelto

The hand-written assembly for libffi on aarch64/windows doesn't emit
unwind information.  If we ever tried to unwind through these functions,
they'd look like leaf functions, which is decidedly not true and would
cause great pain.

For whatever reason, the original aarch64 libffi functions used
x21/x22/x23/x24 as their (callee-saved) scratch registers.  This
convention works on windows as well, but the unwind information on
windows mandates that we start saving callee-saved registers starting
from x19, rather than x21.  Rather than rewriting the assembly to use
x19/x20 instead of x21/x22, which would be a large change, we chose
instead to simply save/restore extra registers in the prolog/epilog.
This change does make the stack frame sizes slightly bigger, but an
extra 16 bytes in libffi stack frames should not matter.

The `-TC` change is necessary to make the compiler play nicely with .asm
file suffixes.

Differential Revision: https://phabricator.services.mozilla.com/D35714

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nathan Froyd 2019-06-27 13:36:48 +00:00
Родитель be0d5d0e09
Коммит 03e51146b9
3 изменённых файлов: 50 добавлений и 46 удалений

13
config/external/ffi/moz.build поставляемый
Просмотреть файл

@ -78,7 +78,18 @@ else:
elif CONFIG['FFI_TARGET'] == 'AARCH64':
ffi_srcs = ('sysv.S', 'ffi.c')
elif CONFIG['FFI_TARGET'] == 'ARM64_WIN64':
ffi_srcs = ('win64.asm', 'ffi.c')
ffi_srcs = ['ffi.c']
GENERATED_FILES += ['win64_aarch.asm']
asm = GENERATED_FILES['win64_aarch.asm']
asm.inputs = [
'/js/src/ctypes/libffi/src/aarch64/win64.asm',
'!../../../js/src/ctypes/libffi/fficonfig.h',
'!../../../js/src/ctypes/libffi/include/ffi.h',
]
asm.script = 'preprocess_libffi_asm.py'
asm.flags = ['$(DEFINES)', '$(LOCAL_INCLUDES)']
SOURCES += ['!win64_aarch.asm']
elif CONFIG['FFI_TARGET'] == 'X86':
ffi_srcs = ('ffi.c', 'sysv.S', 'win32.S')
elif CONFIG['FFI_TARGET'] == 'X86_64':

Просмотреть файл

@ -15,7 +15,8 @@ def main(output, input_asm, ffi_h, ffi_config_h, defines, includes):
defines = shlex.split(defines)
includes = shlex.split(includes)
# CPP uses -E which generates #line directives. -EP suppresses them.
cpp = buildconfig.substs['CPP'] + ['-EP']
# -TC forces the compiler to treat the input as C.
cpp = buildconfig.substs['CPP'] + ['-EP'] + ['-TC']
input_asm = mozpath.relpath(input_asm, os.getcwd())
args = cpp + defines + includes + [input_asm]
print(' '.join(args))

Просмотреть файл

@ -19,9 +19,11 @@
;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "ksarm64.h"
;; Hand-converted from the sysv.S file in this directory.
AREA |.text|, CODE, ARM64
TEXTAREA
;; ffi_call_SYSV()
@ -58,30 +60,26 @@
;; This function uses the following stack frame layout:
;; ==
;; saved x30(lr)
;; x29(fp)-> saved x29(fp)
;; saved x24
;; saved x23
;; saved x22
;; sp' -> saved x21
;; saved x21
;; saved x20
;; saved x19
;; saved x30(lr)
;; x29(fp)-> saved x29(fp)
;; ...
;; sp -> (constructed callee stack arguments)
;; ==
;; Voila!
EXPORT |ffi_call_SYSV|
NESTED_ENTRY |ffi_call_SYSV|
|ffi_call_SYSV| PROC
;#define ffi_call_SYSV_FS (8 * 4)
stp x29, x30, [sp, #-16]!
mov x29, sp
sub sp, sp, #32 ; ffi_call_SYSV_FS
stp x21, x22, [sp, #0]
stp x23, x24, [sp, #16]
PROLOG_SAVE_REG_PAIR x29, x30, #-64!
PROLOG_SAVE_REG_PAIR x19, x20, #16
PROLOG_SAVE_REG_PAIR x21, x22, #32
PROLOG_SAVE_REG_PAIR x23, x24, #48
mov x21, x1
mov x22, x2
@ -145,19 +143,14 @@ noload_call
nosave_call
; All done, unwind our stack frame.
ldp x21, x22, [x29, # - 32] ; ffi_call_SYSV_FS
EPILOG_STACK_RESTORE
EPILOG_RESTORE_REG_PAIR x19, x20, #16
EPILOG_RESTORE_REG_PAIR x21, x22, #32
EPILOG_RESTORE_REG_PAIR x23, x24, #48
EPILOG_RESTORE_REG_PAIR x29, x30, #64!
EPILOG_RETURN
ldp x23, x24, [x29, # - 32 + 16] ; ffi_call_SYSV_FS
mov sp, x29
ldp x29, x30, [sp], #16
ret
ENDP
; #define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
NESTED_END |ffi_call_SYSV|
;; ffi_closure_SYSV
@ -186,10 +179,12 @@ nosave_call
;; This function uses the following stack frame layout:
;; ==
;; saved x30(lr)
;; x29(fp)-> saved x29(fp)
;; saved x22
;; saved x21
;; saved x20
;; saved x19
;; saved x30(lr)
;; x29(fp)-> saved x29(fp)
;; ...
;; sp -> call_context
;; ==
@ -197,16 +192,14 @@ nosave_call
;; Voila!
IMPORT |ffi_closure_SYSV_inner|
EXPORT |ffi_closure_SYSV|
|ffi_closure_SYSV| PROC
stp x29, x30, [sp, #-16]!
NESTED_ENTRY |ffi_closure_SYSV|
mov x29, sp
PROLOG_SAVE_REG_PAIR fp, lr, #-48!
PROLOG_SAVE_REG_PAIR x19, x20, #16
PROLOG_SAVE_REG_PAIR x21, x22, #32
sub sp, sp, #256+512+16
stp x21, x22, [x29, #-16]
sub sp, sp, #256+512
; Load x21 with &call_context.
mov x21, sp
@ -260,13 +253,12 @@ noload_closure
; Note nothing useful is returned in x8.
; We are done, unwind our frame.
ldp x21, x22, [x29, #-16]
EPILOG_STACK_RESTORE
EPILOG_RESTORE_REG_PAIR x19, x20, #16
EPILOG_RESTORE_REG_PAIR x21, x22, #32
EPILOG_RESTORE_REG_PAIR x29, x30, #48!
EPILOG_RETURN
mov sp, x29
NESTED_END |ffi_closure_SYSV|
ldp x29, x30, [sp], #16
ret
ENDP
END
END