diff mbox

[1/3] linux-user: Handle ELFv2 PPC64 binaries in user mode.

Message ID 1399537603-6905-2-git-send-email-dougkwan@google.com
State New
Headers show

Commit Message

Doug Kwan (關振德) May 8, 2014, 8:26 a.m. UTC
Look at ELF header to determin ABI version on PPC64.  This is required
for executing the first instruction correctly.

Signed-off-by: Doug Kwan <dougkwan@google.com>
---
 include/elf.h        |  5 +++++
 linux-user/elfload.c | 17 +++++++++++++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

Comments

Alexander Graf May 8, 2014, 8:36 a.m. UTC | #1
On 05/08/2014 10:26 AM, Doug Kwan wrote:
> Look at ELF header to determin ABI version on PPC64.  This is required
> for executing the first instruction correctly.
>
> Signed-off-by: Doug Kwan <dougkwan@google.com>
> ---
>   include/elf.h        |  5 +++++
>   linux-user/elfload.c | 17 +++++++++++++++--
>   2 files changed, 20 insertions(+), 2 deletions(-)
>
> diff --git a/include/elf.h b/include/elf.h
> index 1599ab2..b39f5db 100644
> --- a/include/elf.h
> +++ b/include/elf.h
> @@ -561,6 +561,11 @@ typedef struct {
>   #define SHF_ALPHA_GPREL		0x10000000
>   
>   
> +/* PowerPC specific definitions.  */
> +
> +/* Processor specific flags for the ELF header e_flags field.  */
> +#define EF_PPC64_ABI		3

Please write bitmasks in hex.

> +
>   /* PowerPC relocations defined by the ABIs */
>   #define R_PPC_NONE		0
>   #define R_PPC_ADDR32		1	/* 32bit absolute address */
> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
> index 995f999..b96d64a 100644
> --- a/linux-user/elfload.c
> +++ b/linux-user/elfload.c
> @@ -777,12 +777,18 @@ static uint32_t get_elf_hwcap(void)
>           NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
>       } while (0)
>   
> +static inline uint32_t get_ppc64_abi(struct image_info *infop);
> +
>   static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
>   {
>       _regs->gpr[1] = infop->start_stack;
>   #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
> -    _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
> -    infop->entry = ldq_raw(infop->entry) + infop->load_bias;
> +    if (get_ppc64_abi(infop) < 2) {
> +      _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
> +      infop->entry = ldq_raw(infop->entry) + infop->load_bias;
> +    } else {
> +      _regs->gpr[12] = infop->entry;  /* r12 set to global entry address */

Uli, is this correct? Also, why don't w need to adjust for the load_bias 
with ELFv2 anymore?

> +    }
>   #endif
>       _regs->nip = infop->entry;
>   }
> @@ -1152,6 +1158,13 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
>   
>   #include "elf.h"
>   
> +#ifdef TARGET_PPC
> +static inline uint32_t get_ppc64_abi(struct image_info *infop)
> +{
> +  return infop->elf_flags & EF_PPC64_ABI;
> +}
> +#endif

I'm not sure this is more readable than doing it inline ... :).


Alex
Doug Kwan (關振德) May 8, 2014, 8:43 a.m. UTC | #2
Hi


On Thu, May 8, 2014 at 1:36 AM, Alexander Graf <agraf@suse.de> wrote:
   3
>
>
> Please write bitmasks in hex.

Will fix.



>  +
>>   /* PowerPC relocations defined by the ABIs */
>>   #define R_PPC_NONE            0
>>   #define R_PPC_ADDR32          1       /* 32bit absolute address */
>> diff --git a/linux-user/elfload.c b/linux-user/elfload.c
>> index 995f999..b96d64a 100644
>> --- a/linux-user/elfload.c
>> +++ b/linux-user/elfload.c
>> @@ -777,12 +777,18 @@ static uint32_t get_elf_hwcap(void)
>>           NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
>>       } while (0)
>>   +static inline uint32_t get_ppc64_abi(struct image_info *infop);
>> +
>>   static inline void init_thread(struct target_pt_regs *_regs, struct
>> image_info *infop)
>>   {
>>       _regs->gpr[1] = infop->start_stack;
>>   #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
>> -    _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
>> -    infop->entry = ldq_raw(infop->entry) + infop->load_bias;
>> +    if (get_ppc64_abi(infop) < 2) {
>> +      _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
>> +      infop->entry = ldq_raw(infop->entry) + infop->load_bias;
>> +    } else {
>> +      _regs->gpr[12] = infop->entry;  /* r12 set to global entry address
>> */
>>
>
> Uli, is this correct? Also, why don't w need to adjust for the load_bias
> with ELFv2 anymore?

No.  This is a bug.  It was not caught by testing because load_bias is 0 I
guess.


>
>  +    }
>>   #endif
>>       _regs->nip = infop->entry;
>>   }
>> @@ -1152,6 +1158,13 @@ static inline void init_thread(struct
>> target_pt_regs *regs, struct image_info *i
>>     #include "elf.h"
>>   +#ifdef TARGET_PPC
>> +static inline uint32_t get_ppc64_abi(struct image_info *infop)
>> +{
>> +  return infop->elf_flags & EF_PPC64_ABI;
>> +}
>> +#endif
>>
>
> I'm not sure this is more readable than doing it inline ... :).
>

This is done so because the elf header is not yet included before the
callee.  To eliminate this I need to move the include before ppc's
init_thread.  Is that okay?

Thanks for the comments.

-Doug
Alexander Graf May 8, 2014, 8:45 a.m. UTC | #3
On 05/08/2014 10:43 AM, Doug Kwan (關振德) wrote:
> Hi
>
>
> On Thu, May 8, 2014 at 1:36 AM, Alexander Graf <agraf@suse.de 
> <mailto:agraf@suse.de>> wrote:      3
>
>
>     Please write bitmasks in hex.
>
> Will fix.
>
>         +
>           /* PowerPC relocations defined by the ABIs */
>           #define R_PPC_NONE            0
>           #define R_PPC_ADDR32          1       /* 32bit absolute
>         address */
>         diff --git a/linux-user/elfload.c b/linux-user/elfload.c
>         index 995f999..b96d64a 100644
>         --- a/linux-user/elfload.c
>         +++ b/linux-user/elfload.c
>         @@ -777,12 +777,18 @@ static uint32_t get_elf_hwcap(void)
>                   NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);    \
>               } while (0)
>           +static inline uint32_t get_ppc64_abi(struct image_info *infop);
>         +
>           static inline void init_thread(struct target_pt_regs *_regs,
>         struct image_info *infop)
>           {
>               _regs->gpr[1] = infop->start_stack;
>           #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
>         -    _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
>         -    infop->entry = ldq_raw(infop->entry) + infop->load_bias;
>         +    if (get_ppc64_abi(infop) < 2) {
>         +      _regs->gpr[2] = ldq_raw(infop->entry + 8) +
>         infop->load_bias;
>         +      infop->entry = ldq_raw(infop->entry) + infop->load_bias;
>         +    } else {
>         +      _regs->gpr[12] = infop->entry;  /* r12 set to global
>         entry address */
>
>
>     Uli, is this correct? Also, why don't w need to adjust for the
>     load_bias with ELFv2 anymore?
>
> No.  This is a bug.  It was not caught by testing because load_bias is 
> 0 I guess.
>
>
>         +    }
>           #endif
>               _regs->nip = infop->entry;
>           }
>         @@ -1152,6 +1158,13 @@ static inline void init_thread(struct
>         target_pt_regs *regs, struct image_info *i
>             #include "elf.h"
>           +#ifdef TARGET_PPC
>         +static inline uint32_t get_ppc64_abi(struct image_info *infop)
>         +{
>         +  return infop->elf_flags & EF_PPC64_ABI;
>         +}
>         +#endif
>
>
>     I'm not sure this is more readable than doing it inline ... :).
>
>
> This is done so because the elf header is not yet included before the 
> callee.  To eliminate this I need to move the include before ppc's 
> init_thread.  Is that okay?

Ah, I see. I don't have strong feelings either way. Riku, what would you 
prefer?


Alex
Ulrich Weigand May 8, 2014, 1:30 p.m. UTC | #4
Doug Kwan (關振德) <dougkwan@google.com> wrote on 08.05.2014 10:43:14:

On Thu, May 8, 2014 at 1:36 AM, Alexander Graf <agraf@suse.de> wrote:
>> -    _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;

>> -    infop->entry = ldq_raw(infop->entry) + infop->load_bias;

>> +    if (get_ppc64_abi(infop) < 2) {

>> +      _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;

>> +      infop->entry = ldq_raw(infop->entry) + infop->load_bias;

>> +    } else {

>> +      _regs->gpr[12] = infop->entry;  /* r12 set to global entry

address */
>>

>> Uli, is this correct? Also, why don't w need to adjust for the

>> load_bias with ELFv2 anymore?

>

> No.  This is a bug.  It was not caught by testing because load_bias

> is 0 I guess.


Actually, it looks correct to me.  The value of infop->entry itself
was presumably already adjusted for the load bias by common code.

However, on ELFv1, that value points to the descriptor, but the values
we *load* from that descriptor *also* need to be adjusted by the load
bias, since the image has not yet been relocated at this stage.

With ELFv2, the (already adjusted) infop->entry value points directly
to the code, so no further adjustment is required.

Bye,
Ulrich
diff mbox

Patch

diff --git a/include/elf.h b/include/elf.h
index 1599ab2..b39f5db 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -561,6 +561,11 @@  typedef struct {
 #define SHF_ALPHA_GPREL		0x10000000
 
 
+/* PowerPC specific definitions.  */
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_PPC64_ABI		3
+
 /* PowerPC relocations defined by the ABIs */
 #define R_PPC_NONE		0
 #define R_PPC_ADDR32		1	/* 32bit absolute address */
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 995f999..b96d64a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -777,12 +777,18 @@  static uint32_t get_elf_hwcap(void)
         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
     } while (0)
 
+static inline uint32_t get_ppc64_abi(struct image_info *infop);
+
 static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
 {
     _regs->gpr[1] = infop->start_stack;
 #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-    _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
-    infop->entry = ldq_raw(infop->entry) + infop->load_bias;
+    if (get_ppc64_abi(infop) < 2) {
+      _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_bias;
+      infop->entry = ldq_raw(infop->entry) + infop->load_bias;
+    } else {
+      _regs->gpr[12] = infop->entry;  /* r12 set to global entry address */
+    }
 #endif
     _regs->nip = infop->entry;
 }
@@ -1152,6 +1158,13 @@  static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
 
 #include "elf.h"
 
+#ifdef TARGET_PPC
+static inline uint32_t get_ppc64_abi(struct image_info *infop)
+{
+  return infop->elf_flags & EF_PPC64_ABI;
+}
+#endif
+
 struct exec
 {
     unsigned int a_info;   /* Use macros N_MAGIC, etc for access */