func nacladdr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { if p.As == ALEAL || p.As == ALEAQ { return } if a.Reg == REG_BP { ctxt.Diag("invalid address: %v", p) return } if a.Reg == REG_TLS { a.Reg = REG_BP } if a.Type == obj.TYPE_MEM && a.Name == obj.NAME_NONE { switch a.Reg { // all ok case REG_BP, REG_SP, REG_R15: break default: if a.Index != REG_NONE { ctxt.Diag("invalid address %v", p) } a.Index = a.Reg if a.Index != REG_NONE { a.Scale = 1 } a.Reg = REG_R15 } } }
// registerIndirect parses the general form of a register indirection. // It is can be (R1), (R2*scale), or (R1)(R2*scale) where R1 may be a simple // register or register pair R:R or (R, R) or (R+R). // Or it might be a pseudo-indirection like (FP). // We are sitting on the opening parenthesis. func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) { p.get('(') tok := p.next() name := tok.String() r1, r2, scale, ok := p.register(name, 0) if !ok { p.errorf("indirect through non-register %s", tok) } p.get(')') a.Type = obj.TYPE_MEM if r1 < 0 { // Pseudo-register reference. if r2 != 0 { p.errorf("cannot use pseudo-register in pair") return } // For SB, SP, and FP, there must be a name here. 0(FP) is not legal. if name != "PC" && a.Name == obj.NAME_NONE { p.errorf("cannot reference %s without a symbol", name) } p.setPseudoRegister(a, name, false, prefix) return } a.Reg = r1 if r2 != 0 { // TODO: Consistency in the encoding would be nice here. if p.arch.Thechar == '5' || p.arch.Thechar == '7' { // Special form // ARM: destination register pair (R1, R2). // ARM64: register pair (R1, R2) for LDP/STP. if prefix != 0 || scale != 0 { p.errorf("illegal address mode for register pair") return } a.Type = obj.TYPE_REGREG a.Offset = int64(r2) // Nothing may follow return } if p.arch.Thechar == '9' { // Special form for PPC64: (R1+R2); alias for (R1)(R2*1). if prefix != 0 || scale != 0 { p.errorf("illegal address mode for register+register") return } a.Type = obj.TYPE_MEM a.Scale = 1 a.Index = r2 // Nothing may follow. return } } if r2 != 0 { p.errorf("indirect through register pair") } if prefix == '$' { a.Type = obj.TYPE_ADDR } if r1 == arch.RPC && prefix != 0 { p.errorf("illegal addressing mode for PC") } if scale == 0 && p.peek() == '(' { // General form (R)(R*scale). p.next() tok := p.next() r1, r2, scale, ok = p.register(tok.String(), 0) if !ok { p.errorf("indirect through non-register %s", tok) } if r2 != 0 { p.errorf("unimplemented two-register form") } a.Index = r1 a.Scale = int16(scale) p.get(')') } else if scale != 0 { // First (R) was missing, all we have is (R*scale). a.Reg = 0 a.Index = r1 a.Scale = int16(scale) } }