libmach
diff --git a/src/libmach/loc.c b/src/libmach/loc.c
new file mode 100644
index 0000000..47bcf3d
--- /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;
+}
+