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;
+}
+