diff mbox

[v4,04/19] x86/boot/reloc: reduce assembly usage as much as possible

Message ID 1470438282-4226-5-git-send-email-daniel.kiper@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Daniel Kiper Aug. 5, 2016, 11:04 p.m. UTC
Next patch will leave just required jmp instruction
in xen/x86/boot/reloc.c.

Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 xen/arch/x86/boot/build32.lds |    1 +
 xen/arch/x86/boot/build32.mk  |    2 +-
 xen/arch/x86/boot/reloc.c     |   52 ++++++++++++++++++++---------------------
 3 files changed, 27 insertions(+), 28 deletions(-)

Comments

Jan Beulich Aug. 11, 2016, 1:56 p.m. UTC | #1
>>> On 06.08.16 at 01:04, <daniel.kiper@oracle.com> wrote:
> Next patch will leave just required jmp instruction
> in xen/x86/boot/reloc.c.

I can't make sense of this now, and it'll get even more problematic
for archaeologists if the two patches don't get committed one right
after the other. Please instead describe what _this_ patch does
and why.

> --- a/xen/arch/x86/boot/build32.lds
> +++ b/xen/arch/x86/boot/build32.lds
> @@ -24,6 +24,7 @@ SECTIONS
>          *(.text)
>          *(.text.*)
>          *(.rodata)
> +        *(.bss)

The suggested change to the earlier patch would make this
unnecessary, but here you get to see even more clearly why
picking just a few sections is bogus.

>  static void *reloc_mbi_struct(void *old, unsigned int bytes)
>  {
>      void *new;
> -    asm(
> -    "    call 1f                      \n"
> -    "1:  pop  %%edx                   \n"
> -    "    mov  alloc-1b(%%edx),%0      \n"
> -    "    sub  %1,%0                   \n"
> -    "    and  $~15,%0                 \n"
> -    "    mov  %0,alloc-1b(%%edx)      \n"
> -    "    mov  %0,%%edi                \n"
> -    "    rep  movsb                   \n"
> -       : "=&r" (new), "+c" (bytes), "+S" (old)
> -	: : "edx", "edi", "memory");
> -    return new;
> +
> +    alloc -= ALIGN_UP(bytes, 16);
> +    new = (void *)alloc;
> +
> +    while ( bytes-- )
> +        *(char *)new++ = *(char *)old++;
> +
> +    return (void *)alloc;
>  }

To further cut down the number of casts, what about making new
have type char * and doing

    while ( bytes-- )
        new[bytes] = ((char *)old)[bytes];

    return new;

One might even argue old could also be of type char * (and actually
be const), but that would only move the cast into the caller. Yet
perhaps that's still better readable than the expression above.

And then, maybe the code could even mostly stay as it is: Is there
anything keeping alloc from being of type void *?

Jan
diff mbox

Patch

diff --git a/xen/arch/x86/boot/build32.lds b/xen/arch/x86/boot/build32.lds
index b14c7d5..a658ca8 100644
--- a/xen/arch/x86/boot/build32.lds
+++ b/xen/arch/x86/boot/build32.lds
@@ -24,6 +24,7 @@  SECTIONS
         *(.text)
         *(.text.*)
         *(.rodata)
+        *(.bss)
   }
 
   /DISCARD/ : {
diff --git a/xen/arch/x86/boot/build32.mk b/xen/arch/x86/boot/build32.mk
index eb02b4b..d54d259 100644
--- a/xen/arch/x86/boot/build32.mk
+++ b/xen/arch/x86/boot/build32.mk
@@ -23,7 +23,7 @@  CFLAGS := $(filter-out -flto,$(CFLAGS))
 	$(OBJDUMP) -h $< | sed -n '/[0-9]/{s,00*,0,g;p;}' |\
 		while read idx name sz rest; do \
 			case "$$name" in \
-			.data|.data.*|.rodata.*|.bss|.bss.*) \
+			.data|.data.*|.rodata.*|.bss.*) \
 				test $$sz != 0 || continue; \
 				echo "Error: non-empty $$name: 0x$$sz" >&2; \
 				exit $$(expr $$idx + 1);; \
diff --git a/xen/arch/x86/boot/reloc.c b/xen/arch/x86/boot/reloc.c
index 63045c0..9ae42e2 100644
--- a/xen/arch/x86/boot/reloc.c
+++ b/xen/arch/x86/boot/reloc.c
@@ -15,39 +15,33 @@  asm (
     "    .text                         \n"
     "    .globl _start                 \n"
     "_start:                           \n"
-    "    call 1f                       \n"
-    "1:  pop  %ebx                     \n"
-    "    mov  %eax,alloc-1b(%ebx)      \n"
-    "    jmp  reloc                    \n"
-    );
-
-/*
- * This is our data. Because the code must be relocatable, no BSS is
- * allowed. All data is accessed PC-relative with inline assembly.
- */
-asm (
-    "alloc:                            \n"
-    "    .long 0                       \n"
+    "    push %eax                     \n"
+    "    push 0x8(%esp)                \n"
+    "    call reloc                    \n"
+    "    ret  $0x4                     \n"
     );
 
 typedef unsigned int u32;
 #include "../../../include/xen/multiboot.h"
 
+#define __stdcall	__attribute__((__stdcall__))
+
+#define ALIGN_UP(arg, align) \
+                (((arg) + (align) - 1) & ~((typeof(arg))(align) - 1))
+
+static u32 alloc;
+
 static void *reloc_mbi_struct(void *old, unsigned int bytes)
 {
     void *new;
-    asm(
-    "    call 1f                      \n"
-    "1:  pop  %%edx                   \n"
-    "    mov  alloc-1b(%%edx),%0      \n"
-    "    sub  %1,%0                   \n"
-    "    and  $~15,%0                 \n"
-    "    mov  %0,alloc-1b(%%edx)      \n"
-    "    mov  %0,%%edi                \n"
-    "    rep  movsb                   \n"
-       : "=&r" (new), "+c" (bytes), "+S" (old)
-	: : "edx", "edi", "memory");
-    return new;
+
+    alloc -= ALIGN_UP(bytes, 16);
+    new = (void *)alloc;
+
+    while ( bytes-- )
+        *(char *)new++ = *(char *)old++;
+
+    return (void *)alloc;
 }
 
 static char *reloc_mbi_string(char *old)
@@ -58,11 +52,15 @@  static char *reloc_mbi_string(char *old)
     return reloc_mbi_struct(old, p - old + 1);
 }
 
-multiboot_info_t *reloc(multiboot_info_t *mbi_old)
+multiboot_info_t __stdcall *reloc(multiboot_info_t *mbi_old, u32 trampoline)
 {
-    multiboot_info_t *mbi = reloc_mbi_struct(mbi_old, sizeof(*mbi));
+    multiboot_info_t *mbi;
     int i;
 
+    alloc = trampoline;
+
+    mbi = reloc_mbi_struct(mbi_old, sizeof(*mbi));
+
     if ( mbi->flags & MBI_CMDLINE )
         mbi->cmdline = (u32)reloc_mbi_string((char *)mbi->cmdline);