support for relative expressions.

This commit is contained in:
Kelvin Sherlock 2017-01-12 20:55:47 -05:00
parent 11bce44253
commit ff09d63678

View File

@ -407,6 +407,7 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
expression e; expression e;
e.relative = op == REC_RELEXP; e.relative = op == REC_RELEXP;
e.section = current_section;
e.offset = data_ptr->size(); e.offset = data_ptr->size();
e.size = read_8(iter); e.size = read_8(iter);
@ -627,37 +628,80 @@ void append(std::vector<T> &to, unsigned count, const T& value) {
* convert a wdc expression to an omf reloc/interseg record. * convert a wdc expression to an omf reloc/interseg record.
* *
*/ */
inline bool in_range(int value, int low, int high) {
return value >= low && value <= high;
}
void to_omf(const expression &e, omf::segment &seg) { void to_omf(const expression &e, omf::segment &seg) {
if (e.stack.empty()) return; //? if (e.stack.empty() || e.size == 0) {
warnx("Expression empty at segment \"%s\" pc %04x", seg.segname.c_str(), e.offset);
return;
}
if (e.stack.size() == 1 && e.stack[0].tag == OP_VAL) {
uint32_t value = e.stack[0].value;
for(int i = 0; i < e.size; ++i, value >>= 8) if (e.stack.size() == 1) {
auto &a = e.stack[0];
uint32_t value = a.value;
if (e.relative) {
if (a.tag == OP_VAL || a.tag == OP_LOC) {
int tmp = (int)value - (int)e.offset - (int)e.size;
bool ok = false;
if (e.size >= 2 && in_range(tmp, -32768, 32767)) ok = true;
if (e.size == 1 && in_range(tmp, -128, 127)) ok = true;
if (!ok) {
warnx("Relative branch out of range (%d) at segment \"%s\" pc %04x",
tmp, seg.segname.c_str(), e.offset);
flags._errors++;
return;
}
for (int i = 0; i < e.size; ++i, tmp >>= 8)
seg.data[e.offset + i] = tmp & 0xff;
return;
}
warnx("Relative branch error at \"%s\" pc %04x", seg.segname.c_str(), e.offset);
flags._errors++;
return;
}
if (a.tag == OP_VAL) {
for (int i = 0; i < e.size; ++i, value >>= 8)
seg.data[e.offset + i] = value & 0xff; seg.data[e.offset + i] = value & 0xff;
return; return;
} }
if (e.stack.size() == 1 && e.stack[0].tag == OP_LOC) { if (a.tag == OP_LOC) {
auto &loc = e.stack[0]; auto &loc = a;
uint32_t value = loc.value;
if (loc.section == 0) { if (loc.section == 0) {
warnx("Unable to relocate (invalid segment)."); warnx("Invalid segment at \"%s\" pc %04x", seg.segname.c_str(), e.offset);
flags._errors++; flags._errors++;
return; return;
} }
if (loc.section == seg.segnum) { if (loc.section == seg.segnum) {
omf::reloc r; omf::reloc r;
r.size = e.size; r.size = e.size;
r.offset = e.offset; r.offset = e.offset;
r.value = value; r.value = value;
// also store value in data
#if 0
// handle later.
// if generating a super, store inline.
if (!flags._C && r.can_compress()) {
for (int i = 0; i < e.size; ++i, value >>= 8) for (int i = 0; i < e.size; ++i, value >>= 8)
seg.data[e.offset + i] = value & 0xff; seg.data[e.offset + i] = value & 0xff;
}
#endif
seg.relocs.emplace_back(r); seg.relocs.emplace_back(r);
} else { } else {
omf::interseg r; omf::interseg r;
@ -667,31 +711,33 @@ void to_omf(const expression &e, omf::segment &seg) {
r.segment_offset = loc.value; r.segment_offset = loc.value;
seg.intersegs.emplace_back(r); seg.intersegs.emplace_back(r);
// if generating super, store
} }
return; return;
} }
if (e.stack.size() == 3 // error handled below.
&& e.stack[0].tag == OP_LOC }
&& e.stack[1].tag == OP_VAL
&& (e.stack[2].tag == OP_SHL || e.stack[2].tag == OP_SHR)) {
if (e.stack.size() == 3) {
auto &loc = e.stack[0]; auto &loc = e.stack[0];
auto &shift = e.stack[1]; auto &shift = e.stack[1];
auto &op = e.stack[2]; auto &op = e.stack[2];
if (loc.tag == OP_LOC && shift.tag == OP_VAL && (op.tag == OP_SHL || op.tag == OP_SHR)) {
if (shift.value > 24) { if (shift.value > 24) {
warnx("shift %d", shift.value); warnx("Shift %d at \"%s\" pc %04x", shift.value, seg.segname.c_str(), e.offset);
for(int i = 0; i < e.size; ++i) // data is already pre-zeroed.
seg.data[e.offset +i] = 0;
return; return;
} }
if (loc.section == 0) { if (loc.section == 0) {
warnx("Unable to relocate expression (invalid segment)."); warnx("Invalid segment at \"%s\" pc %04x", seg.segname.c_str(), e.offset);
flags._errors++; flags._errors++;
return; return;
} }
@ -712,9 +758,11 @@ void to_omf(const expression &e, omf::segment &seg) {
r.value = loc.value; r.value = loc.value;
r.shift = shift_value; r.shift = shift_value;
#if 0
// also store value in data // also store value in data
for (int i = 0; i < e.size; ++i, value >>= 8) for (int i = 0; i < e.size; ++i, value >>= 8)
seg.data[e.offset + i] = value & 0xff; seg.data[e.offset + i] = value & 0xff;
#endif
seg.relocs.emplace_back(r); seg.relocs.emplace_back(r);
} else { } else {
@ -729,8 +777,10 @@ void to_omf(const expression &e, omf::segment &seg) {
} }
return; return;
} }
}
warnx("Relocation expression too complex."); warnx("Expression too complex at \"%s\" pc %04x", seg.segname.c_str(), e.offset);
// should also pretty-print the expression.
flags._errors++; flags._errors++;
return; return;