diff options
Diffstat (limited to 'src/libmach/loc.c')
| -rw-r--r-- | src/libmach/loc.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/src/libmach/loc.c b/src/libmach/loc.c new file mode 100644 index 00000000..47bcf3d9 --- /dev/null +++ b/src/libmach/loc.c @@ -0,0 +1,253 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> + +int +locfmt(Fmt *fmt) +{ + Loc l; + + l = va_arg(fmt->args, Loc); + switch(l.type){ + default: + return fmtprint(fmt, "<loc%d>", l.type); + case LCONST: + return fmtprint(fmt, "0x%lux", l.addr); + case LADDR: + return fmtprint(fmt, "*0x%lux", l.addr); + case LOFFSET: + return fmtprint(fmt, "%ld(%s)", l.offset, l.reg); + case LREG: + return fmtprint(fmt, "%s", l.reg); + } +} + +int +loccmp(Loc *a, Loc *b) +{ + int i; + + if(a->type < b->type) + return -1; + if(a->type > b->type) + return 1; + switch(a->type){ + default: + return 0; + case LADDR: + if(a->addr < b->addr) + return -1; + if(a->addr > b->addr) + return 1; + return 0; + case LOFFSET: + i = strcmp(a->reg, b->reg); + if(i != 0) + return i; + if(a->offset < b->offset) + return -1; + if(a->offset > b->offset) + return 1; + return 0; + case LREG: + return strcmp(a->reg, b->reg); + } +} + +int +lget1(Map *map, Regs *regs, Loc loc, uchar *a, uint n) +{ + if(locsimplify(map, regs, loc, &loc) < 0) + return -1; + if(loc.type == LADDR) + return get1(map, loc.addr, a, n); + /* could do more here - i'm lazy */ + werrstr("bad location for lget1"); + return -1; +} + +int +lget2(Map *map, Regs *regs, Loc loc, u16int *u) +{ + ulong ul; + + if(locsimplify(map, regs, loc, &loc) < 0) + return -1; + if(loc.type == LADDR) + return get2(map, loc.addr, u); + if(loc.type == LCONST){ + *u = loc.addr; + return 0; + } + if(loc.type == LREG){ + if(rget(regs, loc.reg, &ul) < 0) + return -1; + *u = ul; + return 0; + } + werrstr("bad location for lget2"); + return -1; +} + +int +lget4(Map *map, Regs *regs, Loc loc, u32int *u) +{ + ulong ul; + + if(locsimplify(map, regs, loc, &loc) < 0) + return -1; + if(loc.type == LADDR) + return get4(map, loc.addr, u); + if(loc.type == LCONST){ + *u = loc.addr; + return 0; + } + if(loc.type == LREG){ + if(rget(regs, loc.reg, &ul) < 0) + return -1; + *u = ul; + return 0; + } + werrstr("bad location for lget4"); + return -1; +} + +int +lget8(Map *map, Regs *regs, Loc loc, u64int *u) +{ + ulong ul; + + if(locsimplify(map, regs, loc, &loc) < 0) + return -1; + if(loc.type == LADDR) + return get8(map, loc.addr, u); + if(loc.type == LCONST){ + *u = loc.addr; + return 0; + } + if(loc.type == LREG){ + if(rget(regs, loc.reg, &ul) < 0) + return -1; + *u = ul; + return 0; + } + werrstr("bad location for lget8"); + return -1; +} + +int +lput1(Map *map, Regs *regs, Loc loc, uchar *a, uint n) +{ + if(locsimplify(map, regs, loc, &loc) < 0) + return -1; + if(loc.type == LADDR) + return put1(map, loc.addr, a, n); + /* could do more here - i'm lazy */ + werrstr("bad location for lput1"); + return -1; +} + +int +lput2(Map *map, Regs *regs, Loc loc, u16int u) +{ + if(locsimplify(map, regs, loc, &loc) < 0) + return -1; + if(loc.type == LADDR) + return put2(map, loc.addr, u); + if(loc.type == LREG) + return rput(regs, loc.reg, u); + werrstr("bad location for lput2"); + return -1; +} + +int +lput4(Map *map, Regs *regs, Loc loc, u32int u) +{ + if(locsimplify(map, regs, loc, &loc) < 0) + return -1; + if(loc.type == LADDR) + return put4(map, loc.addr, u); + if(loc.type == LREG) + return rput(regs, loc.reg, u); + werrstr("bad location for lput4"); + return -1; +} + +int +lput8(Map *map, Regs *regs, Loc loc, u64int u) +{ + if(locsimplify(map, regs, loc, &loc) < 0) + return -1; + if(loc.type == LADDR) + return put8(map, loc.addr, u); + if(loc.type == LREG) + return rput(regs, loc.reg, u); + werrstr("bad location for lput8"); + return -1; +} + +Loc +locaddr(ulong addr) +{ + Loc l; + + l.type = LADDR; + l.addr = addr; + return l; +} + +Loc +locindir(char *reg, long offset) +{ + Loc l; + + l.type = LOFFSET; + l.reg = reg; + l.offset = offset; + return l; +} + +Loc +locconst(ulong con) +{ + Loc l; + + l.type = LCONST; + l.addr = con; + return l; +} + +Loc +locnone(void) +{ + Loc l; + + l.type = LNONE; + return l; +} + +Loc +locreg(char *reg) +{ + Loc l; + + l.type = LREG; + l.reg = reg; + return l; +} + +int +locsimplify(Map *map, Regs *regs, Loc loc, Loc *newloc) +{ + ulong u; + + if(loc.type == LOFFSET){ + if(rget(regs, loc.reg, &u) < 0) + return -1; + *newloc = locaddr(u + loc.offset); + }else + *newloc = loc; + return 0; +} + |
