Replace pointer casts with calls to (read|write)(16|32|64)le.

This stops UBSan from giving runtime misaligned address errors
and might eventually allow building on a non-little-endian host.
This commit is contained in:
Edmund Grimley Evans 2015-11-19 18:21:14 +00:00
parent 5d496b1695
commit 553242c18a
5 changed files with 185 additions and 170 deletions

View File

@ -110,7 +110,7 @@ ST_FUNC void o(unsigned int c)
int ind1 = ind + 4; int ind1 = ind + 4;
if (ind1 > cur_text_section->data_allocated) if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1); section_realloc(cur_text_section, ind1);
*(uint32_t *)(cur_text_section->data + ind) = c; write32le(cur_text_section->data + ind, c);
ind = ind1; ind = ind1;
} }
@ -237,12 +237,12 @@ ST_FUNC void gsym_addr(int t_, int a_)
uint32_t t = t_; uint32_t t = t_;
uint32_t a = a_; uint32_t a = a_;
while (t) { while (t) {
uint32_t *ptr = (uint32_t *)(cur_text_section->data + t); unsigned char *ptr = cur_text_section->data + t;
uint32_t next = *ptr; uint32_t next = read32le(ptr);
if (a - t + 0x8000000 >= 0x10000000) if (a - t + 0x8000000 >= 0x10000000)
tcc_error("branch out of range"); tcc_error("branch out of range");
*ptr = (a - t == 4 ? 0xd503201f : // nop write32le(ptr, (a - t == 4 ? 0xd503201f : // nop
0x14000000 | ((a - t) >> 2 & 0x3ffffff)); // b 0x14000000 | ((a - t) >> 2 & 0x3ffffff))); // b
t = next; t = next;
} }
} }
@ -1177,8 +1177,7 @@ ST_FUNC void gen_va_arg(CType *t)
o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack
b2 = ind; o(0x14000000); // b lab2 b2 = ind; o(0x14000000); // b lab2
// lab1: // lab1:
*(uint32_t *)(cur_text_section->data + b1) = write32le(cur_text_section->data + b1, 0x5400000d | (ind - b1) << 3);
(0x5400000d | (ind - b1) << 3);
o(0xb9001c00 | r1 | r0 << 5); // str w(r1),[x(r0),#28] // __vr_offs o(0xb9001c00 | r1 | r0 << 5); // str w(r1),[x(r0),#28] // __vr_offs
o(0xf9400800 | r1 | r0 << 5); // ldr x(r1),[x(r0),#16] // __vr_top o(0xf9400800 | r1 | r0 << 5); // ldr x(r1),[x(r0),#16] // __vr_top
if (hfa == 1 || fsize == 16) if (hfa == 1 || fsize == 16)
@ -1198,8 +1197,7 @@ ST_FUNC void gen_va_arg(CType *t)
(uint32_t)(hfa != 3) << 21); // st(hfa) {v28.(s|d),...}[0],[x(r1)] (uint32_t)(hfa != 3) << 21); // st(hfa) {v28.(s|d),...}[0],[x(r1)]
} }
// lab2: // lab2:
*(uint32_t *)(cur_text_section->data + b2) = write32le(cur_text_section->data + b2, 0x14000000 | (ind - b2) >> 2);
(0x14000000 | (ind - b2) >> 2);
} }
} }
@ -1259,14 +1257,13 @@ ST_FUNC void gfunc_epilog(void)
{ {
if (loc) { if (loc) {
// Insert instructions to subtract size of stack frame from SP. // Insert instructions to subtract size of stack frame from SP.
uint32_t *ptr = unsigned char *ptr = cur_text_section->data + arm64_func_sub_sp_offset;
(uint32_t *)(cur_text_section->data + arm64_func_sub_sp_offset);
uint64_t diff = (-loc + 15) & ~15; uint64_t diff = (-loc + 15) & ~15;
if (!(diff >> 24)) { if (!(diff >> 24)) {
if (diff & 0xfff) // sub sp,sp,#(diff & 0xfff) if (diff & 0xfff) // sub sp,sp,#(diff & 0xfff)
ptr[0] = 0xd10003ff | (diff & 0xfff) << 10; write32le(ptr, 0xd10003ff | (diff & 0xfff) << 10);
if (diff >> 12) // sub sp,sp,#(diff >> 12),lsl #12 if (diff >> 12) // sub sp,sp,#(diff >> 12),lsl #12
ptr[1] = 0xd14003ff | (diff >> 12) << 10; write32le(ptr + 4, 0xd14003ff | (diff >> 12) << 10);
} }
else { else {
// In this case we may subtract more than necessary, // In this case we may subtract more than necessary,
@ -1281,9 +1278,9 @@ ST_FUNC void gfunc_epilog(void)
diff = (diff + 1) >> 1; diff = (diff + 1) >> 1;
++j; ++j;
} }
ptr[0] = 0xd2800010 | diff << 5 | i << 21; write32le(ptr, 0xd2800010 | diff << 5 | i << 21);
// mov x16,#(diff),lsl #(16 * i) // mov x16,#(diff),lsl #(16 * i)
ptr[1] = 0xcb3063ff | j << 10; write32le(ptr + 4, 0xcb3063ff | j << 10);
// sub sp,sp,x16,lsl #(j) // sub sp,sp,x16,lsl #(j)
} }
} }
@ -1805,8 +1802,7 @@ ST_FUNC void gen_clear_cache(void)
lab1 = ind; lab1 = ind;
o(0xd50b7b20 | p); // dc cvau,x(p) o(0xd50b7b20 | p); // dc cvau,x(p)
o(0x8b000000 | p | p << 5 | dsz << 16); // add x(p),x(p),x(dsz) o(0x8b000000 | p | p << 5 | dsz << 16); // add x(p),x(p),x(dsz)
*(uint32_t *)(cur_text_section->data + b1) = write32le(cur_text_section->data + b1, 0x14000000 | (ind - b1) >> 2);
(0x14000000 | (ind - b1) >> 2);
o(0xeb00001f | p << 5 | end << 16); // cmp x(p),x(end) o(0xeb00001f | p << 5 | end << 16); // cmp x(p),x(end)
o(0x54ffffa3 | ((lab1 - ind) << 3 & 0xffffe0)); // b.cc lab1 o(0x54ffffa3 | ((lab1 - ind) << 3 & 0xffffe0)); // b.cc lab1
o(0xd5033b9f); // dsb ish o(0xd5033b9f); // dsb ish
@ -1816,8 +1812,7 @@ ST_FUNC void gen_clear_cache(void)
lab1 = ind; lab1 = ind;
o(0xd50b7520 | p); // ic ivau,x(p) o(0xd50b7520 | p); // ic ivau,x(p)
o(0x8b000000 | p | p << 5 | isz << 16); // add x(p),x(p),x(isz) o(0x8b000000 | p | p << 5 | isz << 16); // add x(p),x(p),x(isz)
*(uint32_t *)(cur_text_section->data + b1) = write32le(cur_text_section->data + b1, 0x14000000 | (ind - b1) >> 2);
(0x14000000 | (ind - b1) >> 2);
o(0xeb00001f | p << 5 | end << 16); // cmp x(p),x(end) o(0xeb00001f | p << 5 | end << 16); // cmp x(p),x(end)
o(0x54ffffa3 | ((lab1 - ind) << 3 & 0xffffe0)); // b.cc lab1 o(0x54ffffa3 | ((lab1 - ind) << 3 & 0xffffe0)); // b.cc lab1
o(0xd5033b9f); // dsb ish o(0xd5033b9f); // dsb ish

View File

@ -138,11 +138,10 @@ ST_FUNC void gen_le32(int c)
/* output a symbol and patch all calls to it */ /* output a symbol and patch all calls to it */
ST_FUNC void gsym_addr(int t, int a) ST_FUNC void gsym_addr(int t, int a)
{ {
int n, *ptr;
while (t) { while (t) {
ptr = (int *)(cur_text_section->data + t); unsigned char *ptr = cur_text_section->data + t;
n = *ptr; /* next value */ uint32_t n = read32le(ptr); /* next value */
*ptr = a - t - 4; write32le(ptr, a - t - 4);
t = n; t = n;
} }
} }
@ -165,7 +164,7 @@ ST_FUNC int oad(int c, int s)
ind1 = ind + 4; ind1 = ind + 4;
if (ind1 > cur_text_section->data_allocated) if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1); section_realloc(cur_text_section, ind1);
*(int *)(cur_text_section->data + ind) = s; write32le(cur_text_section->data + ind, s);
s = ind; s = ind;
ind = ind1; ind = ind1;
return s; return s;
@ -671,9 +670,7 @@ ST_FUNC void gjmp_addr(int a)
/* generate a test. set 'inv' to invert test. Stack entry is popped */ /* generate a test. set 'inv' to invert test. Stack entry is popped */
ST_FUNC int gtst(int inv, int t) ST_FUNC int gtst(int inv, int t)
{ {
int v, t1, *p; int v = vtop->r & VT_VALMASK;
v = vtop->r & VT_VALMASK;
if (v == VT_CMP) { if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */ /* fast case : can jump directly since flags are set */
g(0x0f); g(0x0f);
@ -681,14 +678,12 @@ ST_FUNC int gtst(int inv, int t)
} else if (v == VT_JMP || v == VT_JMPI) { } else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */ /* && or || optimization */
if ((v & 1) == inv) { if ((v & 1) == inv) {
uint32_t n1, n = vtop->c.i;
/* insert vtop->c jump list in t */ /* insert vtop->c jump list in t */
t1 = vtop->c.i; while ((n1 = read32le(cur_text_section->data + n)))
p = &t1; n = n1;
while (*p != 0) write32le(cur_text_section->data + n, t);
p = (int *)(cur_text_section->data + *p); t = vtop->c.i;
*p = t;
vtop->c.i = t1;
t = t1;
} else { } else {
t = gjmp(t); t = gjmp(t);
gsym(vtop->c.i); gsym(vtop->c.i);

45
tcc.h
View File

@ -131,6 +131,51 @@
#include "stab.h" #include "stab.h"
#include "libtcc.h" #include "libtcc.h"
static inline uint16_t read16le(unsigned char *p)
{
return p[0] | (uint16_t)p[1] << 8;
}
static inline void write16le(unsigned char *p, uint16_t x)
{
p[0] = x & 255;
p[1] = x >> 8 & 255;
}
static inline uint32_t read32le(unsigned char *p)
{
return (p[0] | (uint32_t)p[1] << 8 |
(uint32_t)p[2] << 16 | (uint32_t)p[3] << 24);
}
static inline void write32le(unsigned char *p, uint32_t x)
{
p[0] = x & 255;
p[1] = x >> 8 & 255;
p[2] = x >> 16 & 255;
p[3] = x >> 24 & 255;
}
static inline uint64_t read64le(unsigned char *p)
{
return (p[0] | (uint64_t)p[1] << 8 |
(uint64_t)p[2] << 16 | (uint64_t)p[3] << 24 |
(uint64_t)p[4] << 32 | (uint64_t)p[5] << 40 |
(uint64_t)p[6] << 48 | (uint64_t)p[7] << 56);
}
static inline void write64le(unsigned char *p, uint64_t x)
{
p[0] = x & 255;
p[1] = x >> 8 & 255;
p[2] = x >> 16 & 255;
p[3] = x >> 24 & 255;
p[4] = x >> 32 & 255;
p[5] = x >> 40 & 255;
p[6] = x >> 48 & 255;
p[7] = x >> 56 & 255;
}
/* parser debug */ /* parser debug */
/* #define PARSE_DEBUG */ /* #define PARSE_DEBUG */
/* preprocessor debug */ /* preprocessor debug */

213
tccelf.c
View File

@ -528,7 +528,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
qrel++; qrel++;
} }
} }
*(int *)ptr += val; write32le(ptr, read32le(ptr) + val);
break; break;
case R_386_PC32: case R_386_PC32:
if (s1->output_type == TCC_OUTPUT_DLL) { if (s1->output_type == TCC_OUTPUT_DLL) {
@ -541,36 +541,36 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
break; break;
} }
} }
*(int *)ptr += val - addr; write32le(ptr, read32le(ptr) + val - addr);
break; break;
case R_386_PLT32: case R_386_PLT32:
*(int *)ptr += val - addr; write32le(ptr, read32le(ptr) + val - addr);
break; break;
case R_386_GLOB_DAT: case R_386_GLOB_DAT:
case R_386_JMP_SLOT: case R_386_JMP_SLOT:
*(int *)ptr = val; write32le(ptr, val);
break; break;
case R_386_GOTPC: case R_386_GOTPC:
*(int *)ptr += s1->got->sh_addr - addr; write32le(ptr, read32le(ptr) + s1->got->sh_addr - addr);
break; break;
case R_386_GOTOFF: case R_386_GOTOFF:
*(int *)ptr += val - s1->got->sh_addr; write32le(ptr, read32le(ptr) + val - s1->got->sh_addr);
break; break;
case R_386_GOT32: case R_386_GOT32:
/* we load the got offset */ /* we load the got offset */
*(int *)ptr += s1->sym_attrs[sym_index].got_offset; write32le(ptr, read32le(ptr) + s1->sym_attrs[sym_index].got_offset);
break; break;
case R_386_16: case R_386_16:
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
output_file: output_file:
tcc_error("can only produce 16-bit binary files"); tcc_error("can only produce 16-bit binary files");
} }
*(short *)ptr += val; write16le(ptr, read16le(ptr) + val);
break; break;
case R_386_PC16: case R_386_PC16:
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY)
goto output_file; goto output_file;
*(short *)ptr += val - addr; write16le(ptr, read16le(ptr) + val - addr);
break; break;
#elif defined(TCC_TARGET_ARM) #elif defined(TCC_TARGET_ARM)
case R_ARM_PC24: case R_ARM_PC24:
@ -762,38 +762,38 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
break; break;
#elif defined(TCC_TARGET_ARM64) #elif defined(TCC_TARGET_ARM64)
case R_AARCH64_ABS64: case R_AARCH64_ABS64:
*(uint64_t *)ptr = val; write64le(ptr, val);
break; break;
case R_AARCH64_ABS32: case R_AARCH64_ABS32:
*(uint32_t *)ptr = val; write32le(ptr, val);
break; break;
case R_AARCH64_MOVW_UABS_G0_NC: case R_AARCH64_MOVW_UABS_G0_NC:
*(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) | write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
(val & 0xffff) << 5; (val & 0xffff) << 5));
break; break;
case R_AARCH64_MOVW_UABS_G1_NC: case R_AARCH64_MOVW_UABS_G1_NC:
*(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) | write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
(val >> 16 & 0xffff) << 5; (val >> 16 & 0xffff) << 5));
break; break;
case R_AARCH64_MOVW_UABS_G2_NC: case R_AARCH64_MOVW_UABS_G2_NC:
*(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) | write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
(val >> 32 & 0xffff) << 5; (val >> 32 & 0xffff) << 5));
break; break;
case R_AARCH64_MOVW_UABS_G3: case R_AARCH64_MOVW_UABS_G3:
*(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) | write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
(val >> 48 & 0xffff) << 5; (val >> 48 & 0xffff) << 5));
break; break;
case R_AARCH64_ADR_PREL_PG_HI21: { case R_AARCH64_ADR_PREL_PG_HI21: {
uint64_t off = (val >> 12) - (addr >> 12); uint64_t off = (val >> 12) - (addr >> 12);
if ((off + ((uint64_t)1 << 20)) >> 21) if ((off + ((uint64_t)1 << 20)) >> 21)
tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed"); tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
*(uint32_t *)ptr = (*(uint32_t *)ptr & 0x9f00001f) | write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
(off & 0x1ffffc) << 3 | (off & 3) << 29; (off & 0x1ffffc) << 3 | (off & 3) << 29));
break; break;
} }
case R_AARCH64_ADD_ABS_LO12_NC: case R_AARCH64_ADD_ABS_LO12_NC:
*(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffc003ff) | write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
(val & 0xfff) << 10; (val & 0xfff) << 10));
break; break;
case R_AARCH64_JUMP26: case R_AARCH64_JUMP26:
case R_AARCH64_CALL26: case R_AARCH64_CALL26:
@ -812,9 +812,9 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
{ {
tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed (val=%lx, addr=%lx)", addr, val); tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed (val=%lx, addr=%lx)", addr, val);
} }
*(uint32_t *)ptr = 0x14000000 | write32le(ptr, (0x14000000 |
(uint32_t)(type == R_AARCH64_CALL26) << 31 | (uint32_t)(type == R_AARCH64_CALL26) << 31 |
((val - addr) >> 2 & 0x3ffffff); ((val - addr) >> 2 & 0x3ffffff)));
break; break;
case R_AARCH64_ADR_GOT_PAGE: { case R_AARCH64_ADR_GOT_PAGE: {
uint64_t off = uint64_t off =
@ -822,14 +822,15 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12)); s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12));
if ((off + ((uint64_t)1 << 20)) >> 21) if ((off + ((uint64_t)1 << 20)) >> 21)
tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed"); tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed");
*(uint32_t *)ptr = (*(uint32_t *)ptr & 0x9f00001f) | write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
(off & 0x1ffffc) << 3 | (off & 3) << 29; (off & 0x1ffffc) << 3 | (off & 3) << 29));
break; break;
} }
case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_LD64_GOT_LO12_NC:
*(uint32_t *)ptr = (*(uint32_t *)ptr & 0xfff803ff) | write32le(ptr,
((s1->got->sh_addr + s1->sym_attrs[sym_index].got_offset) ((read32le(ptr) & 0xfff803ff) |
& 0xff8) << 7; ((s1->got->sh_addr +
s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7));
break; break;
case R_AARCH64_COPY: case R_AARCH64_COPY:
break; break;
@ -841,7 +842,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
val - rel->r_addend, val - rel->r_addend,
(char *) symtab_section->link->data + sym->st_name); (char *) symtab_section->link->data + sym->st_name);
#endif #endif
*(addr_t *)ptr = val - rel->r_addend; write64le(ptr, val - rel->r_addend);
break; break;
default: default:
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
@ -885,11 +886,11 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
break; break;
} else { } else {
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
qrel->r_addend = *(long long *)ptr + val; qrel->r_addend = read64le(ptr) + val;
qrel++; qrel++;
} }
} }
*(long long *)ptr += val; write64le(ptr, read64le(ptr) + val);
break; break;
case R_X86_64_32: case R_X86_64_32:
case R_X86_64_32S: case R_X86_64_32S:
@ -897,10 +898,10 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
/* XXX: this logic may depend on TCC's codegen /* XXX: this logic may depend on TCC's codegen
now TCC uses R_X86_64_32 even for a 64bit pointer */ now TCC uses R_X86_64_32 even for a 64bit pointer */
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
qrel->r_addend = *(int *)ptr + val; qrel->r_addend = read32le(ptr) + val;
qrel++; qrel++;
} }
*(int *)ptr += val; write32le(ptr, read32le(ptr) + val);
break; break;
case R_X86_64_PC32: case R_X86_64_PC32:
@ -910,7 +911,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
if (esym_index) { if (esym_index) {
qrel->r_offset = rel->r_offset; qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32); qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32);
qrel->r_addend = *(int *)ptr; qrel->r_addend = read32le(ptr);
qrel++; qrel++;
break; break;
} }
@ -931,24 +932,25 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
if (diff < -2147483648LL || diff > 2147483647LL) { if (diff < -2147483648LL || diff > 2147483647LL) {
tcc_error("internal error: relocation failed"); tcc_error("internal error: relocation failed");
} }
*(int *)ptr += diff; write32le(ptr, read32le(ptr) + diff);
} }
break; break;
case R_X86_64_GLOB_DAT: case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT: case R_X86_64_JUMP_SLOT:
/* They don't need addend */ /* They don't need addend */
*(addr_t *)ptr = val - rel->r_addend; write64le(ptr, val - rel->r_addend);
break; break;
case R_X86_64_GOTPCREL: case R_X86_64_GOTPCREL:
*(int *)ptr += (s1->got->sh_addr - addr + write32le(ptr, read32le(ptr) +
s1->sym_attrs[sym_index].got_offset - 4); (s1->got->sh_addr - addr +
s1->sym_attrs[sym_index].got_offset - 4));
break; break;
case R_X86_64_GOTTPOFF: case R_X86_64_GOTTPOFF:
*(int *)ptr += val - s1->got->sh_addr; write32le(ptr, read32le(ptr) + val - s1->got->sh_addr);
break; break;
case R_X86_64_GOT32: case R_X86_64_GOT32:
/* we load the got offset */ /* we load the got offset */
*(int *)ptr += s1->sym_attrs[sym_index].got_offset; write32le(ptr, read32le(ptr) + s1->sym_attrs[sym_index].got_offset);
break; break;
#else #else
#error unsupported processor #error unsupported processor
@ -1032,23 +1034,6 @@ static struct sym_attr *alloc_sym_attr(TCCState *s1, int index)
return &s1->sym_attrs[index]; return &s1->sym_attrs[index];
} }
/* XXX: suppress that */
static void put32(unsigned char *p, uint32_t val)
{
p[0] = val;
p[1] = val >> 8;
p[2] = val >> 16;
p[3] = val >> 24;
}
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) || \
defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
static uint32_t get32(unsigned char *p)
{
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
#endif
static void build_got(TCCState *s1) static void build_got(TCCState *s1)
{ {
unsigned char *ptr; unsigned char *ptr;
@ -1061,19 +1046,19 @@ static void build_got(TCCState *s1)
ptr = section_ptr_add(s1->got, 3 * PTR_SIZE); ptr = section_ptr_add(s1->got, 3 * PTR_SIZE);
#if PTR_SIZE == 4 #if PTR_SIZE == 4
/* keep space for _DYNAMIC pointer, if present */ /* keep space for _DYNAMIC pointer, if present */
put32(ptr, 0); write32le(ptr, 0);
/* two dummy got entries */ /* two dummy got entries */
put32(ptr + 4, 0); write32le(ptr + 4, 0);
put32(ptr + 8, 0); write32le(ptr + 8, 0);
#else #else
/* keep space for _DYNAMIC pointer, if present */ /* keep space for _DYNAMIC pointer, if present */
put32(ptr, 0); write32le(ptr, 0);
put32(ptr + 4, 0); write32le(ptr + 4, 0);
/* two dummy got entries */ /* two dummy got entries */
put32(ptr + 8, 0); write32le(ptr + 8, 0);
put32(ptr + 12, 0); write32le(ptr + 12, 0);
put32(ptr + 16, 0); write32le(ptr + 16, 0);
put32(ptr + 20, 0); write32le(ptr + 20, 0);
#endif #endif
} }
@ -1155,10 +1140,10 @@ static unsigned long put_got_entry(TCCState *s1,
p = section_ptr_add(plt, 16); p = section_ptr_add(plt, 16);
p[0] = 0xff; /* pushl got + PTR_SIZE */ p[0] = 0xff; /* pushl got + PTR_SIZE */
p[1] = modrm + 0x10; p[1] = modrm + 0x10;
put32(p + 2, PTR_SIZE); write32le(p + 2, PTR_SIZE);
p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */ p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */
p[7] = modrm; p[7] = modrm;
put32(p + 8, PTR_SIZE * 2); write32le(p + 8, PTR_SIZE * 2);
} }
/* The PLT slot refers to the relocation entry it needs /* The PLT slot refers to the relocation entry it needs
@ -1169,16 +1154,16 @@ static unsigned long put_got_entry(TCCState *s1,
p = section_ptr_add(plt, 16); p = section_ptr_add(plt, 16);
p[0] = 0xff; /* jmp *(got + x) */ p[0] = 0xff; /* jmp *(got + x) */
p[1] = modrm; p[1] = modrm;
put32(p + 2, s1->got->data_offset); write32le(p + 2, s1->got->data_offset);
p[6] = 0x68; /* push $xxx */ p[6] = 0x68; /* push $xxx */
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
/* On x86-64, the relocation is referred to by _index_. */ /* On x86-64, the relocation is referred to by _index_. */
put32(p + 7, relofs / sizeof (ElfW_Rel)); write32le(p + 7, relofs / sizeof (ElfW_Rel));
#else #else
put32(p + 7, relofs); write32le(p + 7, relofs);
#endif #endif
p[11] = 0xe9; /* jmp plt_start */ p[11] = 0xe9; /* jmp plt_start */
put32(p + 12, -(plt->data_offset)); write32le(p + 12, -(plt->data_offset));
/* If this was an UNDEF symbol set the offset in the /* If this was an UNDEF symbol set the offset in the
dynsymtab to the PLT slot, so that PC32 relocs to it dynsymtab to the PLT slot, so that PC32 relocs to it
@ -1200,24 +1185,24 @@ static unsigned long put_got_entry(TCCState *s1,
if (plt->data_offset == 0) { if (plt->data_offset == 0) {
/* first plt entry */ /* first plt entry */
p = section_ptr_add(plt, 16); p = section_ptr_add(plt, 16);
put32(p, 0xe52de004); /* push {lr} */ write32le(p, 0xe52de004); /* push {lr} */
put32(p+4, 0xe59fe010); /* ldr lr, [pc, #16] */ write32le(p+4, 0xe59fe010); /* ldr lr, [pc, #16] */
put32(p+8, 0xe08fe00e); /* add lr, pc, lr */ write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */
put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */ write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
} }
symattr->plt_offset = plt->data_offset; symattr->plt_offset = plt->data_offset;
if (symattr->plt_thumb_stub) { if (symattr->plt_thumb_stub) {
p = section_ptr_add(plt, 20); p = section_ptr_add(plt, 20);
put32(p, 0x4778); /* bx pc */ write32le(p, 0x4778); /* bx pc */
put32(p+2, 0x46c0); /* nop */ write32le(p+2, 0x46c0); /* nop */
p += 4; p += 4;
} else } else
p = section_ptr_add(plt, 16); p = section_ptr_add(plt, 16);
put32(p, 0xe59fc004); /* ldr ip, [pc, #4] ; GOT entry offset */ write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] ; GOT entry offset */
put32(p+4, 0xe08fc00c); /* add ip, pc, ip ; addr of GOT entry */ write32le(p+4, 0xe08fc00c); /* add ip, pc, ip ; addr of GOT entry */
put32(p+8, 0xe59cf000); /* ldr pc, [ip] ; jump to GOT entry */ write32le(p+8, 0xe59cf000); /* ldr pc, [ip] ; jump to GOT entry */
put32(p+12, s1->got->data_offset); /* GOT entry off once patched */ write32le(p+12, s1->got->data_offset); /* GOT entry off once patched */
/* the symbol is modified so that it will be relocated to /* the symbol is modified so that it will be relocated to
the PLT */ the PLT */
@ -1237,8 +1222,8 @@ static unsigned long put_got_entry(TCCState *s1,
section_ptr_add(plt, 32); section_ptr_add(plt, 32);
symattr->plt_offset = plt->data_offset; symattr->plt_offset = plt->data_offset;
p = section_ptr_add(plt, 16); p = section_ptr_add(plt, 16);
put32(p, s1->got->data_offset); write32le(p, s1->got->data_offset);
put32(p + 4, (uint64_t)s1->got->data_offset >> 32); write32le(p + 4, (uint64_t)s1->got->data_offset >> 32);
if (sym->st_shndx == SHN_UNDEF) if (sym->st_shndx == SHN_UNDEF)
offset = plt->data_offset - 16; offset = plt->data_offset - 16;
@ -1381,9 +1366,9 @@ ST_FUNC void build_got_entries(TCCState *s1)
text_section->data_offset + 4, R_ARM_JUMP24, text_section->data_offset + 4, R_ARM_JUMP24,
sym_index); sym_index);
p = section_ptr_add(text_section, 8); p = section_ptr_add(text_section, 8);
put32(p, 0x4778); /* bx pc */ write32le(p, 0x4778); /* bx pc */
put32(p+2, 0x46c0); /* nop */ write32le(p+2, 0x46c0); /* nop */
put32(p+4, 0xeafffffe); /* b $sym */ write32le(p+4, 0xeafffffe); /* b $sym */
} }
#elif defined(TCC_TARGET_ARM64) #elif defined(TCC_TARGET_ARM64)
//xx Other cases may be required here: //xx Other cases may be required here:
@ -1595,7 +1580,7 @@ ST_FUNC void tcc_add_bcheck(TCCState *s1)
Section *init_section = find_section(s1, ".init"); Section *init_section = find_section(s1, ".init");
unsigned char *pinit = section_ptr_add(init_section, 5); unsigned char *pinit = section_ptr_add(init_section, 5);
pinit[0] = 0xe8; pinit[0] = 0xe8;
put32(pinit + 1, -4); write32le(pinit + 1, -4);
put_elf_reloc(symtab_section, init_section, put_elf_reloc(symtab_section, init_section,
init_section->data_offset - 4, R_386_PC32, sym_index); init_section->data_offset - 4, R_386_PC32, sym_index);
} }
@ -1761,9 +1746,9 @@ ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
section_reserve(s1->got, offset + PTR_SIZE); section_reserve(s1->got, offset + PTR_SIZE);
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
/* only works for x86-64 */ /* only works for x86-64 */
put32(s1->got->data + offset + 4, sym->st_value >> 32); write32le(s1->got->data + offset + 4, sym->st_value >> 32);
#endif #endif
put32(s1->got->data + offset, sym->st_value & 0xffffffff); write32le(s1->got->data + offset, sym->st_value & 0xffffffff);
} }
/* Perform relocation to GOT or PLT entries */ /* Perform relocation to GOT or PLT entries */
@ -1930,20 +1915,20 @@ ST_FUNC void relocate_plt(TCCState *s1)
p_end = p + s1->plt->data_offset; p_end = p + s1->plt->data_offset;
if (p < p_end) { if (p < p_end) {
#if defined(TCC_TARGET_I386) #if defined(TCC_TARGET_I386)
put32(p + 2, get32(p + 2) + s1->got->sh_addr); write32le(p + 2, read32le(p + 2) + s1->got->sh_addr);
put32(p + 8, get32(p + 8) + s1->got->sh_addr); write32le(p + 8, read32le(p + 8) + s1->got->sh_addr);
p += 16; p += 16;
while (p < p_end) { while (p < p_end) {
put32(p + 2, get32(p + 2) + s1->got->sh_addr); write32le(p + 2, read32le(p + 2) + s1->got->sh_addr);
p += 16; p += 16;
} }
#elif defined(TCC_TARGET_X86_64) #elif defined(TCC_TARGET_X86_64)
int x = s1->got->sh_addr - s1->plt->sh_addr - 6; int x = s1->got->sh_addr - s1->plt->sh_addr - 6;
put32(p + 2, get32(p + 2) + x); write32le(p + 2, read32le(p + 2) + x);
put32(p + 8, get32(p + 8) + x - 6); write32le(p + 8, read32le(p + 8) + x - 6);
p += 16; p += 16;
while (p < p_end) { while (p < p_end) {
put32(p + 2, get32(p + 2) + x + s1->plt->data - p); write32le(p + 2, read32le(p + 2) + x + s1->plt->data - p);
p += 16; p += 16;
} }
#elif defined(TCC_TARGET_ARM) #elif defined(TCC_TARGET_ARM)
@ -1951,9 +1936,9 @@ ST_FUNC void relocate_plt(TCCState *s1)
x=s1->got->sh_addr - s1->plt->sh_addr - 12; x=s1->got->sh_addr - s1->plt->sh_addr - 12;
p += 16; p += 16;
while (p < p_end) { while (p < p_end) {
if (get32(p) == 0x46c04778) /* PLT Thumb stub present */ if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */
p += 4; p += 4;
put32(p + 12, x + get32(p + 12) + s1->plt->data - p); write32le(p + 12, x + read32le(p + 12) + s1->plt->data - p);
p += 16; p += 16;
} }
#elif defined(TCC_TARGET_ARM64) #elif defined(TCC_TARGET_ARM64)
@ -1962,32 +1947,32 @@ ST_FUNC void relocate_plt(TCCState *s1)
uint64_t off = (got >> 12) - (plt >> 12); uint64_t off = (got >> 12) - (plt >> 12);
if ((off + ((uint32_t)1 << 20)) >> 21) if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt); tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt);
put32(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]! write32le(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
put32(p + 4, (0x90000010 | // adrp x16,... write32le(p + 4, (0x90000010 | // adrp x16,...
(off & 0x1ffffc) << 3 | (off & 3) << 29)); (off & 0x1ffffc) << 3 | (off & 3) << 29));
put32(p + 8, (0xf9400211 | // ldr x17,[x16,#...] write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...]
(got & 0xff8) << 7)); (got & 0xff8) << 7));
put32(p + 12, (0x91000210 | // add x16,x16,#... write32le(p + 12, (0x91000210 | // add x16,x16,#...
(got & 0xfff) << 10)); (got & 0xfff) << 10));
put32(p + 16, 0xd61f0220); // br x17 write32le(p + 16, 0xd61f0220); // br x17
put32(p + 20, 0xd503201f); // nop write32le(p + 20, 0xd503201f); // nop
put32(p + 24, 0xd503201f); // nop write32le(p + 24, 0xd503201f); // nop
put32(p + 28, 0xd503201f); // nop write32le(p + 28, 0xd503201f); // nop
p += 32; p += 32;
while (p < p_end) { while (p < p_end) {
uint64_t pc = plt + (p - s1->plt->data); uint64_t pc = plt + (p - s1->plt->data);
uint64_t addr = got + uint64_t addr = got +
(get32(p) | (uint64_t)get32(p + 4) << 32); (read32le(p) | (uint64_t)read32le(p + 4) << 32);
uint32_t off = (addr >> 12) - (pc >> 12); uint32_t off = (addr >> 12) - (pc >> 12);
if ((off + ((uint32_t)1 << 20)) >> 21) if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc); tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
put32(p, (0x90000010 | // adrp x16,... write32le(p, (0x90000010 | // adrp x16,...
(off & 0x1ffffc) << 3 | (off & 3) << 29)); (off & 0x1ffffc) << 3 | (off & 3) << 29));
put32(p + 4, (0xf9400211 | // ldr x17,[x16,#...] write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
(addr & 0xff8) << 7)); (addr & 0xff8) << 7));
put32(p + 8, (0x91000210 | // add x16,x16,#... write32le(p + 8, (0x91000210 | // add x16,x16,#...
(addr & 0xfff) << 10)); (addr & 0xfff) << 10));
put32(p + 12, 0xd61f0220); // br x17 write32le(p + 12, 0xd61f0220); // br x17
p += 16; p += 16;
} }
#elif defined(TCC_TARGET_C67) #elif defined(TCC_TARGET_C67)
@ -2654,7 +2639,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
fill_dynamic(s1, &dyninf); fill_dynamic(s1, &dyninf);
/* put in GOT the dynamic section address and relocate PLT */ /* put in GOT the dynamic section address and relocate PLT */
put32(s1->got->data, dynamic->sh_addr); write32le(s1->got->data, dynamic->sh_addr);
if (file_type == TCC_OUTPUT_EXE if (file_type == TCC_OUTPUT_EXE
#if defined(TCC_OUTPUT_DLL_WITH_PLT) #if defined(TCC_OUTPUT_DLL_WITH_PLT)
|| file_type == TCC_OUTPUT_DLL || file_type == TCC_OUTPUT_DLL

View File

@ -214,11 +214,10 @@ void orex(int ll, int r, int r2, int b)
/* output a symbol and patch all calls to it */ /* output a symbol and patch all calls to it */
void gsym_addr(int t, int a) void gsym_addr(int t, int a)
{ {
int n, *ptr;
while (t) { while (t) {
ptr = (int *)(cur_text_section->data + t); unsigned char *ptr = cur_text_section->data + t;
n = *ptr; /* next value */ uint32_t n = read32le(ptr); /* next value */
*ptr = a - t - 4; write32le(ptr, a - t - 4);
t = n; t = n;
} }
} }
@ -248,7 +247,7 @@ ST_FUNC int oad(int c, int s)
ind1 = ind + 4; ind1 = ind + 4;
if (ind1 > cur_text_section->data_allocated) if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1); section_realloc(cur_text_section, ind1);
*(int *)(cur_text_section->data + ind) = s; write32le(cur_text_section->data + ind, s);
s = ind; s = ind;
ind = ind1; ind = ind1;
return s; return s;
@ -1691,9 +1690,7 @@ void gjmp_addr(int a)
/* generate a test. set 'inv' to invert test. Stack entry is popped */ /* generate a test. set 'inv' to invert test. Stack entry is popped */
int gtst(int inv, int t) int gtst(int inv, int t)
{ {
int v, t1, *p; int v = vtop->r & VT_VALMASK;
v = vtop->r & VT_VALMASK;
if (v == VT_CMP) { if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */ /* fast case : can jump directly since flags are set */
if (vtop->c.i & 0x100) if (vtop->c.i & 0x100)
@ -1719,14 +1716,12 @@ int gtst(int inv, int t)
} else if (v == VT_JMP || v == VT_JMPI) { } else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */ /* && or || optimization */
if ((v & 1) == inv) { if ((v & 1) == inv) {
uint32_t n1, n = vtop->c.i;
/* insert vtop->c jump list in t */ /* insert vtop->c jump list in t */
t1 = vtop->c.i; while ((n1 = read32le(cur_text_section->data + n)))
p = &t1; n = n1;
while (*p != 0) write32le(cur_text_section->data + n, t);
p = (int *)(cur_text_section->data + *p); t = vtop->c.i;
*p = t;
vtop->c.i = t1;
t = t1;
} else { } else {
t = gjmp(t); t = gjmp(t);
gsym(vtop->c.i); gsym(vtop->c.i);