diff --git a/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S b/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S
index 3c1a461f5e87..d0a5a4c5a37d 100644
--- a/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S
+++ b/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S
@@ -1,10 +1,12 @@
 ///** @file
 //
-//    This code provides low level routines that support the Virtual Machine
-//   for option ROMs.
+//  This code provides low level routines that support the Virtual Machine
+//  for option ROMs.
 //
-//  Copyright (c) 2015, The Linux Foundation. All rights reserved.
+//  Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+//  Copyright (c) 2015, The Linux Foundation. All rights reserved.<BR>
 //  Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+//
 //  This program and the accompanying materials
 //  are licensed and made available under the terms and conditions of the BSD License
 //  which accompanies this distribution.  The full text of the license may be found at
@@ -15,9 +17,10 @@
 //
 //**/
 
-ASM_GLOBAL ASM_PFX(CopyMem);
-ASM_GLOBAL ASM_PFX(EbcInterpret);
-ASM_GLOBAL ASM_PFX(ExecuteEbcImageEntryPoint);
+ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret);
+ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint);
+
+ASM_GLOBAL ASM_PFX(mEbcInstructionBufferTemplate);
 
 //****************************************************************************
 // EbcLLCALLEX
@@ -30,102 +33,121 @@ ASM_GLOBAL ASM_PFX(ExecuteEbcImageEntryPoint);
 //
 //****************************************************************************
 // UINTN EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
-ASM_GLOBAL ASM_PFX(EbcLLCALLEXNative);
 ASM_PFX(EbcLLCALLEXNative):
-      stp  x19, x20, [sp, #-16]!
-      stp  x29, x30, [sp, #-16]!
-
-      mov  x19, x0
-      mov  x20, sp
-      sub  x2, x2, x1   // Length = NewStackPointer-FramePtr
-      sub  sp, sp, x2
-      sub  sp, sp, #64  // Make sure there is room for at least 8 args in the new stack
-      mov  x0, sp
-
-      bl   CopyMem      // Sp, NewStackPointer, Length
-
-      ldp  x0, x1, [sp], #16
-      ldp  x2, x3, [sp], #16
-      ldp  x4, x5, [sp], #16
-      ldp  x6, x7, [sp], #16
-
-      blr  x19
-
-      mov  sp,  x20
-      ldp  x29, x30, [sp], #16
-      ldp  x19, x20, [sp], #16
-
-      ret
+    mov     x8, x0                 // Preserve x0
+    mov     x9, x1                 // Preserve x1
+
+    //
+    // If the EBC stack frame is smaller than or equal to 64 bytes, we know there
+    // are no stacked arguments #9 and beyond that we need to copy to the native
+    // stack. In this case, we can perform a tail call which is much more
+    // efficient, since there is no need to touch the native stack at all.
+    //
+    sub     x3, x2, x1              // Length = NewStackPointer - FramePtr
+    cmp     x3, #64
+    b.gt    1f
+
+    adr     x0, 0f
+    sub     x0, x0, x3, lsr #1
+    br      x0
+
+    ldr     x7, [x9, #56]
+    ldr     x6, [x9, #48]
+    ldr     x5, [x9, #40]
+    ldr     x4, [x9, #32]
+    ldr     x3, [x9, #24]
+    ldr     x2, [x9, #16]
+    ldr     x1, [x9, #8]
+    ldr     x0, [x9]
+
+0:  br      x8
+
+    //
+    // More than 64 bytes: we need to build the full native stack frame and copy
+    // the part of the VM stack exceeding 64 bytes (which may contain stacked
+    // arguments) to the native stack
+    //
+1:  stp     x29, x30, [sp, #-16]!
+    mov     x29, sp
+
+    //
+    // Ensure that the stack pointer remains 16 byte aligned,
+    // even if the size of the VM stack frame is not a multiple of 16
+    //
+    add     x1, x1, #64             // Skip over [potential] reg params
+    tbz     x3, #3, 2f              // Multiple of 16?
+    ldr     x4, [x2, #-8]!          // No? Then push one word
+    str     x4, [sp, #-16]!         // ... but use two slots
+    b       3f
+
+2:  ldp     x4, x5, [x2, #-16]!
+    stp     x4, x5, [sp, #-16]!
+3:  cmp     x2, x1
+    b.gt    2b
+
+    ldp     x0, x1, [x9]
+    ldp     x2, x3, [x9, #16]
+    ldp     x4, x5, [x9, #32]
+    ldp     x6, x7, [x9, #48]
+
+    blr     x8
+
+    mov     sp, x29
+    ldp     x29, x30, [sp], #16
+    ret
 
 //****************************************************************************
 // EbcLLEbcInterpret
 //
 // This function is called by the thunk code to handle an Native to EBC call
 // This can handle up to 16 arguments (1-8 on in x0-x7, 9-16 are on the stack)
-// x9 contains the Entry point that will be the first argument when
+// x16 contains the Entry point that will be the first argument when
 // EBCInterpret is called.
 //
 //****************************************************************************
-ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret);
 ASM_PFX(EbcLLEbcInterpret):
-    stp  x29, x30, [sp, #-16]!
-
-    // copy the current arguments 9-16 from old location and add arg 7 to stack
-    // keeping 16 byte stack alignment
-    sub sp, sp, #80
-    str x7, [sp]
-    ldr x11, [sp, #96]
-    str x11, [sp, #8]
-    ldr x11, [sp, #104]
-    str x11, [sp, #16]
-    ldr x11, [sp, #112]
-    str x11, [sp, #24]
-    ldr x11, [sp, #120]
-    str x11, [sp, #32]
-    ldr x11, [sp, #128]
-    str x11, [sp, #40]
-    ldr x11, [sp, #136]
-    str x11, [sp, #48]
-    ldr x11, [sp, #144]
-    str x11, [sp, #56]
-    ldr x11, [sp, #152]
-    str x11, [sp, #64]
-
-    // Shift arguments and add entry point and as argument 1
-    mov x7, x6
-    mov x6, x5
-    mov x5, x4
-    mov x4, x3
-    mov x3, x2
-    mov x2, x1
-    mov x1, x0
-    mov x0, x9
-
-    # call C-code
-    bl ASM_PFX(EbcInterpret)
-    add sp, sp, #80
-
-    ldp  x29, x30, [sp], #16
+    stp     x29, x30, [sp, #-16]!
+    mov     x29, sp
+
+    // push the entry point and the address of args #9 - #16 onto the stack
+    add     x17, sp, #16
+    stp     x16, x17, [sp, #-16]!
 
+    // call C-code
+    bl      ASM_PFX(EbcInterpret)
+
+    ldp     x29, x30, [sp, #16]
+    add     sp, sp, #32
     ret
 
 //****************************************************************************
 // EbcLLExecuteEbcImageEntryPoint
 //
 // This function is called by the thunk code to handle the image entry point
-// x9 contains the Entry point that will be the first argument when
+// x16 contains the Entry point that will be the third argument when
 // ExecuteEbcImageEntryPoint is called.
 //
 //****************************************************************************
-ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint);
 ASM_PFX(EbcLLExecuteEbcImageEntryPoint):
-    stp  x29, x30, [sp, #-16]!
-    # build new paramater calling convention
-    mov  x2, x1
-    mov  x1, x0
-    mov  x0, x9
-
-    # call C-code
-    bl ASM_PFX(ExecuteEbcImageEntryPoint)
-    ldp  x29, x30, [sp], #16
-    ret
+    mov     x2, x16
+
+    // tail call to C code
+    b       ASM_PFX(ExecuteEbcImageEntryPoint)
+
+//****************************************************************************
+// mEbcInstructionBufferTemplate
+//****************************************************************************
+    .section    ".rodata", "a"
+    .align      3
+ASM_PFX(mEbcInstructionBufferTemplate):
+    adr     x17, 0f
+    ldp     x16, x17, [x17]
+    br      x17
+
+    //
+    // Add a magic code here to help the VM recognize the thunk.
+    //
+    .long   0xCA112EBC
+
+0:  .quad   0   // EBC_ENTRYPOINT_SIGNATURE
+    .quad   0   // EBC_LL_EBC_ENTRYPOINT_SIGNATURE
diff --git a/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c b/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c
index 23261a070143..d15bbc861f33 100644
--- a/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c
+++ b/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c
@@ -2,8 +2,10 @@
   This module contains EBC support routines that are customized based on
   the target AArch64 processor.
 
-Copyright (c) 2015, The Linux Foundation. All rights reserved.
+Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+Copyright (c) 2015, The Linux Foundation. All rights reserved.<BR>
 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
 which accompanies this distribution.  The full text of the license may be found at
@@ -22,47 +24,16 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //
 #define STACK_REMAIN_SIZE (1024 * 4)
 
-//
-// This is instruction buffer used to create EBC thunk
-//
-#define EBC_MAGIC_SIGNATURE                0xCA112EBCCA112EBCull
-#define EBC_ENTRYPOINT_SIGNATURE           0xAFAFAFAFAFAFAFAFull
-#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE    0xFAFAFAFAFAFAFAFAull
-UINT8  mInstructionBufferTemplate[] = {
-  0x03,  0x00, 0x00, 0x14, //b pc+16
-  //
-  // Add a magic code here to help the VM recognize the thunk..
-  //
-    (UINT8)(EBC_MAGIC_SIGNATURE & 0xFF),
-    (UINT8)((EBC_MAGIC_SIGNATURE >> 8) & 0xFF),
-    (UINT8)((EBC_MAGIC_SIGNATURE >> 16) & 0xFF),
-    (UINT8)((EBC_MAGIC_SIGNATURE >> 24) & 0xFF),
-    (UINT8)((EBC_MAGIC_SIGNATURE >> 32) & 0xFF),
-    (UINT8)((EBC_MAGIC_SIGNATURE >> 40) & 0xFF),
-    (UINT8)((EBC_MAGIC_SIGNATURE >> 48) & 0xFF),
-    (UINT8)((EBC_MAGIC_SIGNATURE >> 56) & 0xFF),
-  0x69, 0x00, 0x00, 0x58, //ldr x9, #32
-  0x8A, 0x00, 0x00, 0x58, //ldr x10, #40
-  0x05, 0x00, 0x00, 0x14, //b pc+32
-    (UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),
-    (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
-    (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
-    (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
-    (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),
-    (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),
-    (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),
-    (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),
-    (UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),
-    (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
-    (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
-    (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
-    (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),
-    (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),
-    (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),
-    (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),
-  0x40, 0x01, 0x1F, 0xD6 //br x10
-
-};
+#pragma pack(1)
+typedef struct {
+  UINT32    Instr[3];
+  UINT32    Magic;
+  UINT64    EbcEntryPoint;
+  UINT64    EbcLlEntryPoint;
+} EBC_INSTRUCTION_BUFFER;
+#pragma pack()
+
+extern CONST EBC_INSTRUCTION_BUFFER       mEbcInstructionBufferTemplate;
 
 /**
   Begin executing an EBC image.
@@ -109,7 +80,6 @@ PushU64 (
   //
   VmPtr->Gpr[0] -= sizeof (UINT64);
   *(UINT64 *) VmPtr->Gpr[0] = Arg;
-  return;
 }
 
 
@@ -118,7 +88,6 @@ PushU64 (
 
   This is a thunk function.
 
-  @param  EntryPoint            The entrypoint of EBC code.
   @param  Arg1                  The 1st argument.
   @param  Arg2                  The 2nd argument.
   @param  Arg3                  The 3rd argument.
@@ -127,14 +96,8 @@ PushU64 (
   @param  Arg6                  The 6th argument.
   @param  Arg7                  The 7th argument.
   @param  Arg8                  The 8th argument.
-  @param  Arg9                  The 9th argument.
-  @param  Arg10                 The 10th argument.
-  @param  Arg11                 The 11th argument.
-  @param  Arg12                 The 12th argument.
-  @param  Arg13                 The 13th argument.
-  @param  Arg14                 The 14th argument.
-  @param  Arg15                 The 15th argument.
-  @param  Arg16                 The 16th argument.
+  @param  EntryPoint            The entrypoint of EBC code.
+  @param  Args9_16[]            Array containing arguments #9 to #16.
 
   @return The value returned by the EBC application we're going to run.
 
@@ -142,7 +105,6 @@ PushU64 (
 UINT64
 EFIAPI
 EbcInterpret (
-  IN UINTN      EntryPoint,
   IN UINTN      Arg1,
   IN UINTN      Arg2,
   IN UINTN      Arg3,
@@ -151,14 +113,8 @@ EbcInterpret (
   IN UINTN      Arg6,
   IN UINTN      Arg7,
   IN UINTN      Arg8,
-  IN UINTN      Arg9,
-  IN UINTN      Arg10,
-  IN UINTN      Arg11,
-  IN UINTN      Arg12,
-  IN UINTN      Arg13,
-  IN UINTN      Arg14,
-  IN UINTN      Arg15,
-  IN UINTN      Arg16
+  IN UINTN      EntryPoint,
+  IN UINTN      Args9_16[]
   )
 {
   //
@@ -222,14 +178,14 @@ EbcInterpret (
   // For the worst case, assume there are 4 arguments passed in registers, store
   // them to VM's stack.
   //
-  PushU64 (&VmContext, (UINT64) Arg16);
-  PushU64 (&VmContext, (UINT64) Arg15);
-  PushU64 (&VmContext, (UINT64) Arg14);
-  PushU64 (&VmContext, (UINT64) Arg13);
-  PushU64 (&VmContext, (UINT64) Arg12);
-  PushU64 (&VmContext, (UINT64) Arg11);
-  PushU64 (&VmContext, (UINT64) Arg10);
-  PushU64 (&VmContext, (UINT64) Arg9);
+  PushU64 (&VmContext, (UINT64) Args9_16[7]);
+  PushU64 (&VmContext, (UINT64) Args9_16[6]);
+  PushU64 (&VmContext, (UINT64) Args9_16[5]);
+  PushU64 (&VmContext, (UINT64) Args9_16[4]);
+  PushU64 (&VmContext, (UINT64) Args9_16[3]);
+  PushU64 (&VmContext, (UINT64) Args9_16[2]);
+  PushU64 (&VmContext, (UINT64) Args9_16[1]);
+  PushU64 (&VmContext, (UINT64) Args9_16[0]);
   PushU64 (&VmContext, (UINT64) Arg8);
   PushU64 (&VmContext, (UINT64) Arg7);
   PushU64 (&VmContext, (UINT64) Arg6);
@@ -281,10 +237,10 @@ EbcInterpret (
 /**
   Begin executing an EBC image.
 
-  @param  EntryPoint       The entrypoint of EBC code.
   @param  ImageHandle      image handle for the EBC application we're executing
   @param  SystemTable      standard system table passed into an driver's entry
                            point
+  @param  EntryPoint       The entrypoint of EBC code.
 
   @return The value returned by the EBC application we're going to run.
 
@@ -292,9 +248,9 @@ EbcInterpret (
 UINT64
 EFIAPI
 ExecuteEbcImageEntryPoint (
-  IN UINTN                EntryPoint,
   IN EFI_HANDLE           ImageHandle,
-  IN EFI_SYSTEM_TABLE     *SystemTable
+  IN EFI_SYSTEM_TABLE     *SystemTable,
+  IN UINTN                EntryPoint
   )
 {
   //
@@ -335,7 +291,7 @@ ExecuteEbcImageEntryPoint (
   if (EFI_ERROR(Status)) {
     return Status;
   }
-  VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+  VmContext.StackTop = (UINT8 *)VmContext.StackPool + (STACK_REMAIN_SIZE);
   VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
   VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];
   VmContext.Gpr[0] -= sizeof (UINTN);
@@ -372,11 +328,6 @@ ExecuteEbcImageEntryPoint (
   VmContext.StackRetAddr  = (UINT64) VmContext.Gpr[0];
 
   //
-  // Entry function needn't access high stack context, simply
-  // put the stack pointer here.
-  //
-
-  //
   // Begin executing the EBC code
   //
   EbcExecute (&VmContext);
@@ -414,10 +365,7 @@ EbcCreateThunks (
   IN  UINT32              Flags
   )
 {
-  UINT8       *Ptr;
-  UINT8       *ThunkBase;
-  UINT32      Index;
-  INT32       ThunkSize;
+  EBC_INSTRUCTION_BUFFER       *InstructionBuffer;
 
   //
   // Check alignment of pointer to EBC code
@@ -426,51 +374,38 @@ EbcCreateThunks (
     return EFI_INVALID_PARAMETER;
   }
 
-  ThunkSize = sizeof(mInstructionBufferTemplate);
-
-  Ptr = AllocatePool (sizeof(mInstructionBufferTemplate));
-
-  if (Ptr == NULL) {
+  InstructionBuffer = AllocatePool (sizeof (EBC_INSTRUCTION_BUFFER));
+  if (InstructionBuffer == NULL) {
     return EFI_OUT_OF_RESOURCES;
   }
-  //
-  //  Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);
-  //
-  // Save the start address so we can add a pointer to it to a list later.
-  //
-  ThunkBase = Ptr;
 
   //
   // Give them the address of our buffer we're going to fix up
   //
-  *Thunk = (VOID *) Ptr;
+  *Thunk = InstructionBuffer;
 
   //
   // Copy whole thunk instruction buffer template
   //
-  CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));
+  CopyMem (InstructionBuffer, &mEbcInstructionBufferTemplate,
+    sizeof (EBC_INSTRUCTION_BUFFER));
 
   //
   // Patch EbcEntryPoint and EbcLLEbcInterpret
   //
-  for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
-    if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {
-      *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;
-    }
-    if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
-      if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
-        *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;
-      } else {
-        *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;
-      }
-    }
+  InstructionBuffer->EbcEntryPoint = (UINT64)EbcEntryPoint;
+  if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
+    InstructionBuffer->EbcLlEntryPoint = (UINT64)EbcLLExecuteEbcImageEntryPoint;
+  } else {
+    InstructionBuffer->EbcLlEntryPoint = (UINT64)EbcLLEbcInterpret;
   }
 
   //
   // Add the thunk to the list for this image. Do this last since the add
   // function flushes the cache for us.
   //
-  EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
+  EbcAddImageThunk (ImageHandle, InstructionBuffer,
+    sizeof (EBC_INSTRUCTION_BUFFER));
 
   return EFI_SUCCESS;
 }
@@ -500,40 +435,15 @@ EbcLLCALLEX (
   IN UINT8        Size
   )
 {
-  UINTN    IsThunk;
-  UINTN    TargetEbcAddr;
-  UINT8    InstructionBuffer[sizeof(mInstructionBufferTemplate)];
-  UINTN    Index;
-  UINTN    IndexOfEbcEntrypoint;
-
-  IsThunk       = 1;
-  TargetEbcAddr = 0;
-  IndexOfEbcEntrypoint = 0;
+  CONST EBC_INSTRUCTION_BUFFER *InstructionBuffer;
 
   //
   // Processor specific code to check whether the callee is a thunk to EBC.
   //
-  CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));
-  //
-  // Fill the signature according to mInstructionBufferTemplate
-  //
-  for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
-    if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {
-      *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;
-      IndexOfEbcEntrypoint = Index;
-    }
-    if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
-      *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;
-    }
-  }
-  //
-  // Check if we need thunk to native
-  //
-  if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {
-    IsThunk = 0;
-  }
+  InstructionBuffer = (EBC_INSTRUCTION_BUFFER *)FuncAddr;
 
-  if (IsThunk == 1){
+  if (CompareMem (InstructionBuffer, &mEbcInstructionBufferTemplate,
+        sizeof(EBC_INSTRUCTION_BUFFER) - 2 * sizeof (UINT64)) == 0) {
     //
     // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
     // put our return address and frame pointer on the VM stack.
@@ -545,14 +455,19 @@ EbcLLCALLEX (
     VmPtr->Gpr[0] -= 8;
     VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
 
-    CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN));
-    VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
+    VmPtr->Ip = (VMIP) InstructionBuffer->EbcEntryPoint;
   } else {
     //
     // The callee is not a thunk to EBC, call native code,
     // and get return value.
     //
-    VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
+    // Note that we will not be able to distinguish which part of the interval
+    // [NewStackPointer, FramePtr) consists of stacked function arguments for
+    // this call, and which part simply consists of locals in the caller's
+    // stack frame. All we know is that there is an 8 byte gap at the top that
+    // we can ignore.
+    //
+    VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr - 8);
 
     //
     // Advance the IP.
