Skip to content

Commit d69182b

Browse files
Add relocation patching for AVR
1 parent 89353e5 commit d69182b

File tree

1 file changed

+211
-1
lines changed

1 file changed

+211
-1
lines changed

librz/bin/format/elf/elf_relocs_patching.c

Lines changed: 211 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// SPDX-License-Identifier: LGPL-3.0-only
55

66
#include "elf.h"
7+
#include "elf/glibc_elf.h"
8+
#include "rz_util/rz_bits.h"
79

810
typedef struct reloc_formular_symbols_t {
911
ut64 A; // Appendend
@@ -1908,6 +1910,212 @@ static void patch_reloc_alpha(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_a
19081910
}
19091911
}
19101912

1913+
static void patch_reloc_avr(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, bool big_endian, const RelocFormularSymbols *fs) {
1914+
rz_return_if_fail(buf_patched && fs);
1915+
1916+
ut8 buf[2] = { 0 };
1917+
st64 offset = 0;
1918+
ut16 opcode = 0;
1919+
ut32 nbytes = 2;
1920+
1921+
ut64 val = fs->S + fs->A;
1922+
1923+
switch (rel_type) {
1924+
case R_AVR_NONE:
1925+
return;
1926+
case R_AVR_32:
1927+
rz_buf_write_ble32_at(buf_patched, patch_addr, val, big_endian);
1928+
break;
1929+
case R_AVR_7_PCREL:
1930+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
1931+
offset = (val - fs->P - 2) / 2;
1932+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0x3F8, offset);
1933+
rz_write_ble16(buf, opcode, big_endian);
1934+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
1935+
break;
1936+
case R_AVR_13_PCREL:
1937+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
1938+
offset = (val - fs->P - 2) / 2;
1939+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xFFF, offset);
1940+
rz_write_ble16(buf, opcode, big_endian);
1941+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
1942+
break;
1943+
case R_AVR_16:
1944+
rz_buf_write_ble16_at(buf_patched, patch_addr, val, big_endian);
1945+
break;
1946+
case R_AVR_16_PM:
1947+
rz_buf_write_ble16_at(buf_patched, patch_addr, val / 2, big_endian);
1948+
break;
1949+
case R_AVR_LO8_LDI:
1950+
/* fall through */
1951+
case R_AVR_LDI:
1952+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
1953+
offset = val & 0xFF;
1954+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
1955+
rz_write_ble16(buf, opcode, big_endian);
1956+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
1957+
break;
1958+
case R_AVR_HI8_LDI:
1959+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
1960+
offset = (val >> 8) & 0xFF;
1961+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
1962+
rz_write_ble16(buf, opcode, big_endian);
1963+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
1964+
break;
1965+
case R_AVR_HH8_LDI:
1966+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
1967+
offset = (val >> 16) & 0xFF;
1968+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
1969+
rz_write_ble16(buf, opcode, big_endian);
1970+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
1971+
break;
1972+
case R_AVR_LO8_LDI_NEG:
1973+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
1974+
offset = (-val) & 0xFF;
1975+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
1976+
rz_write_ble16(buf, opcode, big_endian);
1977+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
1978+
break;
1979+
case R_AVR_HI8_LDI_NEG:
1980+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
1981+
offset = ((-val) >> 8) & 0xFF;
1982+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
1983+
rz_write_ble16(buf, opcode, big_endian);
1984+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
1985+
break;
1986+
case R_AVR_HH8_LDI_NEG:
1987+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
1988+
offset = ((-val) >> 16) & 0xFF;
1989+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
1990+
rz_write_ble16(buf, opcode, big_endian);
1991+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
1992+
break;
1993+
case R_AVR_LO8_LDI_PM:
1994+
/* fall through */
1995+
case R_AVR_LO8_LDI_GS:
1996+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
1997+
offset = val & 0xFF;
1998+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
1999+
rz_write_ble16(buf, opcode, big_endian);
2000+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2001+
break;
2002+
case R_AVR_HI8_LDI_PM:
2003+
/* fall through */
2004+
case R_AVR_HI8_LDI_GS:
2005+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2006+
offset = (val >> 8) & 0xFF;
2007+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
2008+
rz_write_ble16(buf, opcode, big_endian);
2009+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2010+
break;
2011+
case R_AVR_HH8_LDI_PM:
2012+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2013+
offset = (val >> 16) & 0xFF;
2014+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
2015+
rz_write_ble16(buf, opcode, big_endian);
2016+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2017+
break;
2018+
case R_AVR_LO8_LDI_PM_NEG:
2019+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2020+
offset = (-val) & 0xFF;
2021+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
2022+
rz_write_ble16(buf, opcode, big_endian);
2023+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2024+
break;
2025+
case R_AVR_HI8_LDI_PM_NEG:
2026+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2027+
offset = ((-val) >> 8) & 0xFF;
2028+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
2029+
rz_write_ble16(buf, opcode, big_endian);
2030+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2031+
break;
2032+
case R_AVR_HH8_LDI_PM_NEG:
2033+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2034+
offset = ((-val) >> 16) & 0xFF;
2035+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
2036+
rz_write_ble16(buf, opcode, big_endian);
2037+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2038+
break;
2039+
case R_AVR_CALL:
2040+
nbytes = 4;
2041+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2042+
val = val / 2;
2043+
case R_AVR_6:
2044+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2045+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0x2C07, val);
2046+
rz_write_ble16(buf, opcode, big_endian);
2047+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2048+
break;
2049+
case R_AVR_6_ADIW:
2050+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2051+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xCF, val);
2052+
rz_write_ble16(buf, opcode, big_endian);
2053+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2054+
break;
2055+
case R_AVR_MS8_LDI:
2056+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2057+
offset = (val >> 24) & 0xFF;
2058+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
2059+
rz_write_ble16(buf, opcode, big_endian);
2060+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2061+
break;
2062+
case R_AVR_MS8_LDI_NEG:
2063+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2064+
offset = ((-val) >> 24) & 0xFF;
2065+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
2066+
rz_write_ble16(buf, opcode, big_endian);
2067+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2068+
break;
2069+
case R_AVR_8:
2070+
/* fall through */
2071+
case R_AVR_8_LO8:
2072+
offset = val & 0xFF;
2073+
rz_buf_write_ble32_at(buf_patched, patch_addr, offset, big_endian);
2074+
break;
2075+
case R_AVR_8_HI8:
2076+
offset = (val >> 8) & 0xFF;
2077+
rz_buf_write_ble32_at(buf_patched, patch_addr, offset, big_endian);
2078+
break;
2079+
case R_AVR_8_HLO8:
2080+
offset = (val >> 16) & 0xFF;
2081+
rz_buf_write_ble32_at(buf_patched, patch_addr, offset, big_endian);
2082+
break;
2083+
case R_AVR_DIFF8:
2084+
/* fall through */
2085+
case R_AVR_DIFF16:
2086+
/* fall through */
2087+
case R_AVR_DIFF32:
2088+
/* Value already written by assembler */
2089+
break;
2090+
case R_AVR_LDS_STS_16:
2091+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2092+
offset = (val - 0x40) & 0x7F;
2093+
offset = (val & 0x0f) | ((val & 0x30) << 5) | ((val & 0x40) << 2);
2094+
opcode = rz_read_ble16(buf, big_endian) | offset;
2095+
rz_write_ble16(buf, opcode, big_endian);
2096+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2097+
break;
2098+
case R_AVR_PORT6:
2099+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2100+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0x60F, val);
2101+
rz_write_ble16(buf, opcode, big_endian);
2102+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2103+
break;
2104+
case R_AVR_PORT5:
2105+
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
2106+
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF8, val);
2107+
rz_write_ble16(buf, opcode, big_endian);
2108+
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
2109+
break;
2110+
case R_AVR_32_PCREL:
2111+
rz_buf_write_ble32_at(buf_patched, patch_addr, val - fs->P, big_endian);
2112+
break;
2113+
default:
2114+
UNHANDL_DEF("AVR", rel_type);
2115+
break;
2116+
}
2117+
}
2118+
19112119
#undef UNHANDL
19122120
#undef UNHANDL_DEF
19132121

@@ -1977,6 +2185,9 @@ void Elf_(rz_bin_elf_patch_relocation)(RZ_NONNULL ELFOBJ *bin, RZ_NONNULL RzBinE
19772185
case EM_SPARCV9:
19782186
patch_reloc_sparc(bin->buf_patched, patch_addr, rel->type, big_endian, &formular_sym);
19792187
break;
2188+
case EM_AVR:
2189+
patch_reloc_avr(bin->buf_patched, patch_addr, rel->type, big_endian, &formular_sym);
2190+
break;
19802191
case EM_M32: ARCH_MISSING("EM_M32");
19812192
case EM_68K: ARCH_MISSING("EM_68K");
19822193
case EM_88K: ARCH_MISSING("EM_88K");
@@ -2032,7 +2243,6 @@ void Elf_(rz_bin_elf_patch_relocation)(RZ_NONNULL ELFOBJ *bin, RZ_NONNULL RzBinE
20322243
case EM_MMIX: ARCH_MISSING("EM_MMIX");
20332244
case EM_HUANY: ARCH_MISSING("EM_HUANY");
20342245
case EM_PRISM: ARCH_MISSING("EM_PRISM");
2035-
case EM_AVR: ARCH_MISSING("EM_AVR");
20362246
case EM_FR30: ARCH_MISSING("EM_FR30");
20372247
case EM_D10V: ARCH_MISSING("EM_D10V");
20382248
case EM_D30V: ARCH_MISSING("EM_D30V");

0 commit comments

Comments
 (0)