~ubuntu-branches/ubuntu/trusty/grub2/trusty

« back to all changes in this revision

Viewing changes to grub-core/kern/powerpc/dl.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2014-01-16 15:18:04 UTC
  • mfrom: (17.6.38 experimental)
  • Revision ID: package-import@ubuntu.com-20140116151804-3foouk7fpqcq3sxx
Tags: 2.02~beta2-2
* Convert patch handling to git-dpm.
* Add bi-endian support to ELF parser (Tomohiro B Berry).
* Adjust restore_mkdevicemap.patch to mark get_kfreebsd_version as static,
  to appease "gcc -Werror=missing-prototypes".
* Cherry-pick from upstream:
  - Change grub-macbless' manual page section to 8.
* Install grub-glue-efi, grub-macbless, grub-render-label, and
  grub-syslinux2cfg.
* grub-shell: Pass -no-pad to xorriso when building floppy images.

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
  return GRUB_ERR_NONE;
39
39
}
40
40
 
41
 
void
42
 
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
43
 
                                 grub_size_t *got)
44
 
{
45
 
  const Elf_Ehdr *e = ehdr;
46
 
  const Elf_Shdr *s;
47
 
  unsigned i;
48
 
 
49
 
  *tramp = 0;
50
 
  *got = 0;
51
 
 
52
 
  /* Find a symbol table.  */
53
 
  for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
54
 
       i < e->e_shnum;
55
 
       i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
56
 
    if (s->sh_type == SHT_SYMTAB)
57
 
      break;
58
 
 
59
 
  if (i == e->e_shnum)
60
 
    return;
61
 
 
62
 
  for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
63
 
       i < e->e_shnum;
64
 
       i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
65
 
    if (s->sh_type == SHT_RELA)
66
 
      {
67
 
        const Elf_Rela *rel, *max;
68
 
        
69
 
        for (rel = (const Elf_Rela *) ((const char *) e + s->sh_offset),
70
 
               max = rel + s->sh_size / s->sh_entsize;
71
 
             rel < max;
72
 
             rel++)
73
 
          if (ELF_R_TYPE (rel->r_info) == GRUB_ELF_R_PPC_REL24)
74
 
            (*tramp)++;
75
 
        
76
 
      }
77
 
 
78
 
  return;
79
 
}
80
 
 
81
41
/* For low-endian reverse lis and addr_high as well as ori and addr_low. */
82
42
struct trampoline
83
43
{
95
55
    0x4e800420,
96
56
  };
97
57
 
 
58
#pragma GCC diagnostic ignored "-Wcast-align"
 
59
 
 
60
grub_err_t
 
61
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
 
62
                                 grub_size_t *got)
 
63
{
 
64
  const Elf_Ehdr *e = ehdr;
 
65
  const Elf_Shdr *s;
 
66
  unsigned i;
 
67
 
 
68
  *tramp = 0;
 
69
  *got = 0;
 
70
 
 
71
  for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
 
72
       i < e->e_shnum;
 
73
       i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
 
74
    if (s->sh_type == SHT_RELA)
 
75
      {
 
76
        const Elf_Rela *rel, *max;
 
77
        
 
78
        for (rel = (const Elf_Rela *) ((const char *) e + s->sh_offset),
 
79
               max = rel + s->sh_size / s->sh_entsize;
 
80
             rel < max;
 
81
             rel++)
 
82
          if (ELF_R_TYPE (rel->r_info) == GRUB_ELF_R_PPC_REL24)
 
83
            (*tramp)++;
 
84
        
 
85
      }
 
86
 
 
87
  *tramp *= sizeof (struct trampoline);
 
88
 
 
89
  return GRUB_ERR_NONE;
 
90
}
 
91
 
98
92
/* Relocate symbols.  */
99
93
grub_err_t
100
 
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
 
94
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
 
95
                               Elf_Shdr *s, grub_dl_segment_t seg)
101
96
{
102
 
  Elf_Ehdr *e = ehdr;
103
 
  Elf_Shdr *s;
104
 
  Elf_Word entsize;
105
 
  unsigned i;
106
 
  struct trampoline *tptr = mod->tramp;
107
 
 
108
 
  /* Find a symbol table.  */
109
 
  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
110
 
       i < e->e_shnum;
111
 
       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
112
 
    if (s->sh_type == SHT_SYMTAB)
113
 
      break;
114
 
 
115
 
  if (i == e->e_shnum)
116
 
    return grub_error (GRUB_ERR_BAD_MODULE, N_("no symbol table"));
117
 
 
118
 
  entsize = s->sh_entsize;
119
 
 
120
 
  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
121
 
       i < e->e_shnum;
122
 
       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
123
 
    if (s->sh_type == SHT_RELA)
124
 
      {
125
 
        grub_dl_segment_t seg;
126
 
 
127
 
        /* Find the target segment.  */
128
 
        for (seg = mod->segment; seg; seg = seg->next)
129
 
          if (seg->section == s->sh_info)
130
 
            break;
131
 
 
132
 
        if (seg)
 
97
  Elf_Rela *rel, *max;
 
98
 
 
99
  for (rel = (Elf_Rela *) ((char *) ehdr + s->sh_offset),
 
100
         max = (Elf_Rela *) ((char *) rel + s->sh_size);
 
101
       rel < max;
 
102
       rel = (Elf_Rela *) ((char *) rel + s->sh_entsize))
 
103
    {
 
104
      Elf_Word *addr;
 
105
      Elf_Sym *sym;
 
106
      grub_uint32_t value;
 
107
 
 
108
      if (seg->size < rel->r_offset)
 
109
        return grub_error (GRUB_ERR_BAD_MODULE,
 
110
                           "reloc offset is out of the segment");
 
111
 
 
112
      addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset);
 
113
      sym = (Elf_Sym *) ((char *) mod->symtab
 
114
                         + mod->symsize * ELF_R_SYM (rel->r_info));
 
115
 
 
116
      /* On the PPC the value does not have an explicit
 
117
         addend, add it.  */
 
118
      value = sym->st_value + rel->r_addend;
 
119
      switch (ELF_R_TYPE (rel->r_info))
 
120
        {
 
121
        case GRUB_ELF_R_PPC_ADDR16_LO:
 
122
          *(Elf_Half *) addr = value;
 
123
          break;
 
124
 
 
125
        case GRUB_ELF_R_PPC_REL24:
133
126
          {
134
 
            Elf_Rela *rel, *max;
 
127
            Elf_Sword delta = value - (Elf_Word) addr;
135
128
 
136
 
            for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
137
 
                   max = rel + s->sh_size / s->sh_entsize;
138
 
                 rel < max;
139
 
                 rel++)
 
129
            if (delta << 6 >> 6 != delta)
140
130
              {
141
 
                Elf_Word *addr;
142
 
                Elf_Sym *sym;
143
 
                grub_uint32_t value;
144
 
 
145
 
                if (seg->size < rel->r_offset)
146
 
                  return grub_error (GRUB_ERR_BAD_MODULE,
147
 
                                     "reloc offset is out of the segment");
148
 
 
149
 
                addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset);
150
 
                sym = (Elf_Sym *) ((char *) mod->symtab
151
 
                                     + entsize * ELF_R_SYM (rel->r_info));
152
 
 
153
 
                /* On the PPC the value does not have an explicit
154
 
                   addend, add it.  */
155
 
                value = sym->st_value + rel->r_addend;
156
 
                switch (ELF_R_TYPE (rel->r_info))
157
 
                  {
158
 
                  case GRUB_ELF_R_PPC_ADDR16_LO:
159
 
                    *(Elf_Half *) addr = value;
160
 
                    break;
161
 
 
162
 
                  case GRUB_ELF_R_PPC_REL24:
163
 
                    {
164
 
                      Elf_Sword delta = value - (Elf_Word) addr;
165
 
 
166
 
                      if (delta << 6 >> 6 != delta)
167
 
                        {
168
 
                          COMPILE_TIME_ASSERT (sizeof (struct trampoline)
169
 
                                               == GRUB_ARCH_DL_TRAMP_SIZE);
170
 
                          grub_memcpy (tptr, &trampoline_template,
171
 
                                       sizeof (*tptr));
172
 
                          delta = (grub_uint8_t *) tptr - (grub_uint8_t *) addr;
173
 
                          tptr->lis |= (((value) >> 16) & 0xffff);
174
 
                          tptr->ori |= ((value) & 0xffff);
175
 
                          tptr++;
176
 
                        }
 
131
                struct trampoline *tptr = mod->trampptr;
 
132
                grub_memcpy (tptr, &trampoline_template,
 
133
                             sizeof (*tptr));
 
134
                delta = (grub_uint8_t *) tptr - (grub_uint8_t *) addr;
 
135
                tptr->lis |= (((value) >> 16) & 0xffff);
 
136
                tptr->ori |= ((value) & 0xffff);
 
137
                mod->trampptr = tptr + 1;
 
138
              }
177
139
                        
178
 
                      if (delta << 6 >> 6 != delta)
179
 
                        return grub_error (GRUB_ERR_BAD_MODULE,
180
 
                                           "relocation overflow");
181
 
                      *addr = (*addr & 0xfc000003) | (delta & 0x3fffffc);
182
 
                      break;
183
 
                    }
184
 
 
185
 
                  case GRUB_ELF_R_PPC_ADDR16_HA:
186
 
                    *(Elf_Half *) addr = (value + 0x8000) >> 16;
187
 
                    break;
188
 
 
189
 
                  case GRUB_ELF_R_PPC_ADDR32:
190
 
                    *addr = value;
191
 
                    break;
192
 
 
193
 
                  case GRUB_ELF_R_PPC_REL32:
194
 
                    *addr = value - (Elf_Word) addr;
195
 
                    break;
196
 
 
197
 
                  default:
198
 
                    return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
199
 
                                       N_("relocation 0x%x is not implemented yet"),
200
 
                                       ELF_R_TYPE (rel->r_info));
201
 
                  }
202
 
              }
 
140
            if (delta << 6 >> 6 != delta)
 
141
              return grub_error (GRUB_ERR_BAD_MODULE,
 
142
                                 "relocation overflow");
 
143
            *addr = (*addr & 0xfc000003) | (delta & 0x3fffffc);
 
144
            break;
203
145
          }
204
 
      }
 
146
 
 
147
        case GRUB_ELF_R_PPC_ADDR16_HA:
 
148
          *(Elf_Half *) addr = (value + 0x8000) >> 16;
 
149
          break;
 
150
 
 
151
        case GRUB_ELF_R_PPC_ADDR32:
 
152
          *addr = value;
 
153
          break;
 
154
 
 
155
        case GRUB_ELF_R_PPC_REL32:
 
156
          *addr = value - (Elf_Word) addr;
 
157
          break;
 
158
 
 
159
        default:
 
160
          return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 
161
                             N_("relocation 0x%x is not implemented yet"),
 
162
                             ELF_R_TYPE (rel->r_info));
 
163
        }
 
164
    }
205
165
 
206
166
  return GRUB_ERR_NONE;
207
167
}