diff mbox

[v2] xtensa: ldso: coalesce dl_mprotect address ranges

Message ID 1420808819-22641-1-git-send-email-jcmvbkbc@gmail.com
State Superseded
Headers show

Commit Message

Max Filippov Jan. 9, 2015, 1:06 p.m. UTC
This noticeably lowers the number of mprotect calls at program startup,
e.g. for busybox: 7 calls vs 1835 calls.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
Changes v1->v2:
- initialize prev_got_start and prev_got_end in INIT_GOT as well.

 ldso/ldso/xtensa/dl-startup.h | 18 +++++++++++++++++-
 ldso/ldso/xtensa/dl-sysdep.h  | 22 +++++++++++++++++++++-
 2 files changed, 38 insertions(+), 2 deletions(-)

Comments

Chris Zankel Jan. 9, 2015, 7:24 p.m. UTC | #1
Max,
Are the symbols usually ordered in ascending order? Otherwise, would it
also safe time to check if the new range overlaps at the front?

Cheers!
-Chris

On Fri, Jan 9, 2015 at 5:06 AM, Max Filippov <jcmvbkbc@gmail.com> wrote:

> This noticeably lowers the number of mprotect calls at program startup,
> e.g. for busybox: 7 calls vs 1835 calls.
>
> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
> ---
> Changes v1->v2:
> - initialize prev_got_start and prev_got_end in INIT_GOT as well.
>
>  ldso/ldso/xtensa/dl-startup.h | 18 +++++++++++++++++-
>  ldso/ldso/xtensa/dl-sysdep.h  | 22 +++++++++++++++++++++-
>  2 files changed, 38 insertions(+), 2 deletions(-)
>
> diff --git a/ldso/ldso/xtensa/dl-startup.h b/ldso/ldso/xtensa/dl-startup.h
> index b135a4c..c60c9cf 100644
> --- a/ldso/ldso/xtensa/dl-startup.h
> +++ b/ldso/ldso/xtensa/dl-startup.h
> @@ -83,6 +83,7 @@ do { \
>         unsigned long l_addr = tpnt->loadaddr; \
>         Elf32_Word relative_count; \
>         unsigned long rel_addr; \
> +       Elf32_Addr prev_got_start = 0, prev_got_end = 0; \
>         int x; \
>  \
>         got_loc = (xtensa_got_location *) \
> @@ -93,7 +94,22 @@ do { \
>                 got_start = got_loc[x].offset & ~(PAGE_SIZE - 1); \
>                 got_end = ((got_loc[x].offset + got_loc[x].length +
> PAGE_SIZE - 1) \
>                                    & ~(PAGE_SIZE - 1)); \
> -               _dl_mprotect ((void *)(got_start + l_addr), got_end -
> got_start, \
> +               if (got_start >= prev_got_start && got_start <=
> prev_got_end) { \
> +                       if (got_end > prev_got_end) \
> +                               prev_got_end = got_end; \
> +                       continue; \
> +               } else if (prev_got_start != prev_got_end) { \
> +                       _dl_mprotect ((void *)(prev_got_start + l_addr), \
> +                                                 prev_got_end -
> prev_got_start, \
> +                                                 PROT_READ | PROT_WRITE |
> PROT_EXEC); \
> +               } \
> +               prev_got_start = got_start; \
> +               prev_got_end = got_end; \
> +       } \
> +\
> +       if (prev_got_start != prev_got_end) { \
> +               _dl_mprotect ((void *)(prev_got_start + l_addr), \
> +                                         prev_got_end - prev_got_start, \
>                                           PROT_READ | PROT_WRITE |
> PROT_EXEC); \
>         } \
>  \
> diff --git a/ldso/ldso/xtensa/dl-sysdep.h b/ldso/ldso/xtensa/dl-sysdep.h
> index a0ed4e5..958f7ef 100644
> --- a/ldso/ldso/xtensa/dl-sysdep.h
> +++ b/ldso/ldso/xtensa/dl-sysdep.h
> @@ -36,6 +36,7 @@ typedef struct xtensa_got_location_struct {
>    do {
>    \
>      xtensa_got_location *got_loc;
>     \
>      Elf32_Addr l_addr = MODULE->loadaddr;
>     \
> +    Elf32_Addr prev_got_start = 0, prev_got_end = 0;
>    \
>      int x;
>    \
>
>     \
>      got_loc = (xtensa_got_location *)
>     \
> @@ -47,7 +48,26 @@ typedef struct xtensa_got_location_struct {
>         got_start = got_loc[x].offset & ~(PAGE_SIZE - 1);
>    \
>         got_end = ((got_loc[x].offset + got_loc[x].length + PAGE_SIZE -
> 1)    \
>                    & ~(PAGE_SIZE - 1));
>    \
> -       _dl_mprotect ((void *)(got_start + l_addr) , got_end - got_start,
>    \
> +       if (got_start >= prev_got_start && got_start <= prev_got_end)
>    \
> +         {
>    \
> +           if (got_end > prev_got_end)
>    \
> +               prev_got_end = got_end;
>    \
> +           continue;
>    \
> +         }
>    \
> +        else if (prev_got_start != prev_got_end)
>    \
> +         {
>    \
> +           _dl_mprotect ((void *)(prev_got_start + l_addr),
>     \
> +                         prev_got_end - prev_got_start,
>     \
> +                         PROT_READ | PROT_WRITE | PROT_EXEC);
>     \
> +          }
>     \
> +        prev_got_start = got_start;
>     \
> +        prev_got_end = got_end;
>             \
> +      }
>             \
> +
>    \
> +    if (prev_got_start != prev_got_end)
>             \
> +      {
>             \
> +        _dl_mprotect ((void *)(prev_got_start + l_addr),
>    \
> +                     prev_got_end - prev_got_start,
>     \
>                       PROT_READ | PROT_WRITE | PROT_EXEC);
>     \
>        }
>             \
>
>     \
> --
> 1.8.1.4
>
>
Max Filippov Jan. 10, 2015, 1:19 a.m. UTC | #2
Chris,

On Fri, Jan 9, 2015 at 10:24 PM, Chris Zankel <chris@zankel.net> wrote:
> Are the symbols usually ordered in ascending order? Otherwise, would it also
> safe time to check if the new range overlaps at the front?

In binaries that I have -- yes. But coalescing ranges from both sides takes
only one additional conditional move, so I'll send v3 with that. Thanks!

-- Max
diff mbox

Patch

diff --git a/ldso/ldso/xtensa/dl-startup.h b/ldso/ldso/xtensa/dl-startup.h
index b135a4c..c60c9cf 100644
--- a/ldso/ldso/xtensa/dl-startup.h
+++ b/ldso/ldso/xtensa/dl-startup.h
@@ -83,6 +83,7 @@  do { \
 	unsigned long l_addr = tpnt->loadaddr; \
 	Elf32_Word relative_count; \
 	unsigned long rel_addr; \
+	Elf32_Addr prev_got_start = 0, prev_got_end = 0; \
 	int x; \
 \
 	got_loc = (xtensa_got_location *) \
@@ -93,7 +94,22 @@  do { \
 		got_start = got_loc[x].offset & ~(PAGE_SIZE - 1); \
 		got_end = ((got_loc[x].offset + got_loc[x].length + PAGE_SIZE - 1) \
 				   & ~(PAGE_SIZE - 1)); \
-		_dl_mprotect ((void *)(got_start + l_addr), got_end - got_start, \
+		if (got_start >= prev_got_start && got_start <= prev_got_end) { \
+			if (got_end > prev_got_end) \
+				prev_got_end = got_end; \
+			continue; \
+		} else if (prev_got_start != prev_got_end) { \
+			_dl_mprotect ((void *)(prev_got_start + l_addr), \
+						  prev_got_end - prev_got_start, \
+						  PROT_READ | PROT_WRITE | PROT_EXEC); \
+		} \
+		prev_got_start = got_start; \
+		prev_got_end = got_end; \
+	} \
+\
+	if (prev_got_start != prev_got_end) { \
+		_dl_mprotect ((void *)(prev_got_start + l_addr), \
+					  prev_got_end - prev_got_start, \
 					  PROT_READ | PROT_WRITE | PROT_EXEC); \
 	} \
 \
diff --git a/ldso/ldso/xtensa/dl-sysdep.h b/ldso/ldso/xtensa/dl-sysdep.h
index a0ed4e5..958f7ef 100644
--- a/ldso/ldso/xtensa/dl-sysdep.h
+++ b/ldso/ldso/xtensa/dl-sysdep.h
@@ -36,6 +36,7 @@  typedef struct xtensa_got_location_struct {
   do {									      \
     xtensa_got_location *got_loc;					      \
     Elf32_Addr l_addr = MODULE->loadaddr;				      \
+    Elf32_Addr prev_got_start = 0, prev_got_end = 0;			      \
     int x;								      \
 									      \
     got_loc = (xtensa_got_location *)					      \
@@ -47,7 +48,26 @@  typedef struct xtensa_got_location_struct {
 	got_start = got_loc[x].offset & ~(PAGE_SIZE - 1);		      \
 	got_end = ((got_loc[x].offset + got_loc[x].length + PAGE_SIZE - 1)    \
 		   & ~(PAGE_SIZE - 1));					      \
-	_dl_mprotect ((void *)(got_start + l_addr) , got_end - got_start,     \
+	if (got_start >= prev_got_start && got_start <= prev_got_end)	      \
+	  {								      \
+	    if (got_end > prev_got_end)					      \
+		prev_got_end = got_end;					      \
+	    continue;							      \
+	  }								      \
+        else if (prev_got_start != prev_got_end)			      \
+	  {								      \
+	    _dl_mprotect ((void *)(prev_got_start + l_addr),		      \
+			  prev_got_end - prev_got_start,		      \
+			  PROT_READ | PROT_WRITE | PROT_EXEC);		      \
+          }								      \
+        prev_got_start = got_start;					      \
+        prev_got_end = got_end;						      \
+      }									      \
+									      \
+    if (prev_got_start != prev_got_end)					      \
+      {									      \
+        _dl_mprotect ((void *)(prev_got_start + l_addr),		      \
+		      prev_got_end - prev_got_start,			      \
 		      PROT_READ | PROT_WRITE | PROT_EXEC);		      \
       }									      \
 									      \