前言
在学习8051中断时,我发现有这么一种写法:
| |
直觉告诉我,这种写法可能不必要…8051的参数传递类似x86里的__fastcall,参数是尽可能优先通过寄存器传递的。(文档)就算在delay函数中发生了中断,寄存器的值也应该会跟着断点一起保存…吧?口说无凭,我们得想个办法验证一下。
本次复现环境为μVision5.38.0.0 with Microchip AT89C51
尝试
我们仿照上面的代码,但是不对n进行保护现场:
| |
用Keil编译之前,我们先进行一些设置,让他输出带汇编的Listing文件:
- 单击Project - Options for Target ‘Target 1’或
图标 - 进入Listing选项卡,勾选C Compiler Listing并勾选Conditional、Symbols和Assembly Code

修改好之后再编译,我们就会得到一些lst文件。用任意文本编辑器打开main.lst,观察一下:
| |
看起来有点乱,稍微解释一下吧!
- 从 20行开始,就是转换后方便阅读的汇编代码。
;开头的句子是注释,相当于C语言中的//。- 从左开始数的第一列是指令地址,你有没有发现从上往下看这一列是递增的呢?
- 第二列是指令(Instruction),这是可以查表的,想了解可以看看官方文档或者本文末尾附录。操作码里包括了操作码(OpCode)和操作数(Operands)。
- 第三列是助记符,顾名思义就是帮助你记住操作码对应功能的东西。
- 最后一列就是操作数了。他们以逗号分隔开。
那么…
阅读汇编
delay函数
我们可以清楚地看到, C0001是delay函数的入口点,那我们就一行行分析一下。首先, 这里提到n被保存到了R6和R7里面。那么R6是啥,R7又是啥呢?

没错,他们都是寄存器,数据范围是8位。我们的函数参数是unsigned int,是16位的,刚好需要两个寄存器。接下来往下看,
MOV A, R7是什么意思呢?查阅官方文档可以看到,这其实就是赋值操作,相当于A = R7。那么A又是啥呢?
哈哈,还是寄存器。不过A是特殊的,叫做累加器(Accumulator)。累加器的用处就是进行一些运算。和我们要找的东西没关系,我们快速过一遍吧。
DEC R7把R7减去1,
MOV R4, AR6把AR6(R6)赋值给R4。
JNZ是Jump if Not Zero,累加器不为0的时候跳转。在这里意思就是如果R7不为0,就跳转到
C0008。
ORL A,R4的意思是A |= R4,既按位逻辑或。这里的R4是上面的R6,而R6是我们一开始传进来的实参。反正带着源码看,虽然不能完全理解但也大概知道是做了些什么事情了。我们还是回到主题上吧。
经过刚刚的分析,我们可以发现delay函数至少使用了这些寄存器:
- R4
- R6
- R7
- A(累加器)
中断函数
该看下一个函数了。紧挨着delay的就是我们写的中断函数,因为这是中断发生后最先到达的地方,所以大概率编译器会在这里使用魔法吧。快速扫一眼,马上就发现和刚刚的函数不一样:第一行就有一个 PUSH操作。还是老样子,我们打开官方文档:
The PUSH instruction increments the stack pointer and stores the value of the specified byte operand at the internal RAM address indirectly referenced by the stack pointer. No flags are affected by this instruction.
意思就是,PUSH指令会将寄存器中的值压入栈中。这好像有点接近我们要找的东西了,继续往下看,程序依次将 ACC、PSW、AR4、AR6、AR7入栈。
等等,好像看到什么熟悉的东西了?ACC、AR4、AR6、AR7,这不就是delay函数用到的寄存器吗!再往下看,
LCALL完delay马上又把这些寄存器POP了回去。这个不就是我们开始手写的
保护现场吗!事已至此,我们已经找到了标题这个问题的答案了。编译器会自动帮我们进行一部分保护现场的工作,所以编写中断服务程序时无需保存外部函数的形参。好耶可以少写一堆代码了!
官方文档
是的…做了这么多才发现另一个官方文档中有写。
这里的第二点就是上面得到的结论:C51编译器会自动将中断函数中调用的函数所使用的所有寄存器保存至栈上。知道了这点之后也有一些别的启发,比如不能在中断函数中调用太多函数导致爆栈等等。― User's Guides for Keil C51 Development Tools
- When required, the contents of ACC, B, DPH, DPL, and PSW are saved on the stack at function invocation time.
- All working registers used in the interrupt function are stored on the stack if a register bank is not specified with the using attribute.
- The working registers and special registers that were saved on the stack are restored before exiting the function.
- The function is terminated by the 8051 RETI instruction.
碎碎念:其实也不能说做的都是无用功,能直接从最底层的汇编理解编译器做了些什么,然后自己找出答案的过程还是很有趣的!
附录:8051所有指令码
展开内容
| 指令码 | 占用字节 | 助记符 | 操作数 |
|---|---|---|---|
| 00 | 1 | NOP | |
| 01 | 2 | AJMP | addr11 |
| 02 | 3 | LJMP | addr16 |
| 03 | 1 | RR | A |
| 04 | 1 | INC | A |
| 05 | 2 | INC | direct |
| 06 | 1 | INC | @R0 |
| 07 | 1 | INC | @R1 |
| 08 | 1 | INC | R0 |
| 09 | 1 | INC | R1 |
| 0A | 1 | INC | R2 |
| 0B | 1 | INC | R3 |
| 0C | 1 | INC | R4 |
| 0D | 1 | INC | R5 |
| 0E | 1 | INC | R6 |
| 0F | 1 | INC | R7 |
| 10 | 3 | JBC | bit, offset |
| 11 | 2 | ACALL | addr11 |
| 12 | 3 | LCALL | addr16 |
| 13 | 1 | RRC | A |
| 14 | 1 | DEC | A |
| 15 | 2 | DEC | direct |
| 16 | 1 | DEC | @R0 |
| 17 | 1 | DEC | @R1 |
| 18 | 1 | DEC | R0 |
| 19 | 1 | DEC | R1 |
| 1A | 1 | DEC | R2 |
| 1B | 1 | DEC | R3 |
| 1C | 1 | DEC | R4 |
| 1D | 1 | DEC | R5 |
| 1E | 1 | DEC | R6 |
| 1F | 1 | DEC | R7 |
| 20 | 3 | JB | bit, offset |
| 21 | 2 | AJMP | addr11 |
| 22 | 1 | RET | |
| 23 | 1 | RL | A |
| 24 | 2 | ADD | A, #immed |
| 25 | 2 | ADD | A, direct |
| 26 | 1 | ADD | A, @R0 |
| 27 | 1 | ADD | A, @R1 |
| 28 | 1 | ADD | A, R0 |
| 29 | 1 | ADD | A, R1 |
| 2A | 1 | ADD | A, R2 |
| 2B | 1 | ADD | A, R3 |
| 2C | 1 | ADD | A, R4 |
| 2D | 1 | ADD | A, R5 |
| 2E | 1 | ADD | A, R6 |
| 2F | 1 | ADD | A, R7 |
| 30 | 3 | JNB | bit, offset |
| 31 | 2 | ACALL | addr11 |
| 32 | 1 | RETI | |
| 33 | 1 | RLC | A |
| 34 | 2 | ADDC | A, #immed |
| 35 | 2 | ADDC | A, direct |
| 36 | 1 | ADDC | A, @R0 |
| 37 | 1 | ADDC | A, @R1 |
| 38 | 1 | ADDC | A, R0 |
| 39 | 1 | ADDC | A, R1 |
| 3A | 1 | ADDC | A, R2 |
| 3B | 1 | ADDC | A, R3 |
| 3C | 1 | ADDC | A, R4 |
| 3D | 1 | ADDC | A, R5 |
| 3E | 1 | ADDC | A, R6 |
| 3F | 1 | ADDC | A, R7 |
| 40 | 2 | JC | offset |
| 41 | 2 | AJMP | addr11 |
| 42 | 2 | ORL | direct, A |
| 43 | 3 | ORL | direct, #immed |
| 44 | 2 | ORL | A, #immed |
| 45 | 2 | ORL | A, direct |
| 46 | 1 | ORL | A, @R0 |
| 47 | 1 | ORL | A, @R1 |
| 48 | 1 | ORL | A, R0 |
| 49 | 1 | ORL | A, R1 |
| 4A | 1 | ORL | A, R2 |
| 4B | 1 | ORL | A, R3 |
| 4C | 1 | ORL | A, R4 |
| 4D | 1 | ORL | A, R5 |
| 4E | 1 | ORL | A, R6 |
| 4F | 1 | ORL | A, R7 |
| 50 | 2 | JNC | offset |
| 51 | 2 | ACALL | addr11 |
| 52 | 2 | ANL | direct, A |
| 53 | 3 | ANL | direct, #immed |
| 54 | 2 | ANL | A, #immed |
| 55 | 2 | ANL | A, direct |
| 56 | 1 | ANL | A, @R0 |
| 57 | 1 | ANL | A, @R1 |
| 58 | 1 | ANL | A, R0 |
| 59 | 1 | ANL | A, R1 |
| 5A | 1 | ANL | A, R2 |
| 5B | 1 | ANL | A, R3 |
| 5C | 1 | ANL | A, R4 |
| 5D | 1 | ANL | A, R5 |
| 5E | 1 | ANL | A, R6 |
| 5F | 1 | ANL | A, R7 |
| 60 | 2 | JZ | offset |
| 61 | 2 | AJMP | addr11 |
| 62 | 2 | XRL | direct, A |
| 63 | 3 | XRL | direct, #immed |
| 64 | 2 | XRL | A, #immed |
| 65 | 2 | XRL | A, direct |
| 66 | 1 | XRL | A, @R0 |
| 67 | 1 | XRL | A, @R1 |
| 68 | 1 | XRL | A, R0 |
| 69 | 1 | XRL | A, R1 |
| 6A | 1 | XRL | A, R2 |
| 6B | 1 | XRL | A, R3 |
| 6C | 1 | XRL | A, R4 |
| 6D | 1 | XRL | A, R5 |
| 6E | 1 | XRL | A, R6 |
| 6F | 1 | XRL | A, R7 |
| 70 | 2 | JNZ | offset |
| 71 | 2 | ACALL | addr11 |
| 72 | 2 | ORL | C, bit |
| 73 | 1 | JMP | @A+DPTR |
| 74 | 2 | MOV | A, #immed |
| 75 | 3 | MOV | direct, #immed |
| 76 | 2 | MOV | @R0, #immed |
| 77 | 2 | MOV | @R1, #immed |
| 78 | 2 | MOV | R0, #immed |
| 79 | 2 | MOV | R1, #immed |
| 7A | 2 | MOV | R2, #immed |
| 7B | 2 | MOV | R3, #immed |
| 7C | 2 | MOV | R4, #immed |
| 7D | 2 | MOV | R5, #immed |
| 7E | 2 | MOV | R6, #immed |
| 7F | 2 | MOV | R7, #immed |
| 80 | 2 | SJMP | offset |
| 81 | 2 | AJMP | addr11 |
| 82 | 2 | ANL | C, bit |
| 83 | 1 | MOVC | A, @A+PC |
| 84 | 1 | DIV | AB |
| 85 | 3 | MOV | direct, direct |
| 86 | 2 | MOV | direct, @R0 |
| 87 | 2 | MOV | direct, @R1 |
| 88 | 2 | MOV | direct, R0 |
| 89 | 2 | MOV | direct, R1 |
| 8A | 2 | MOV | direct, R2 |
| 8B | 2 | MOV | direct, R3 |
| 8C | 2 | MOV | direct, R4 |
| 8D | 2 | MOV | direct, R5 |
| 8E | 2 | MOV | direct, R6 |
| 8F | 2 | MOV | direct, R7 |
| 90 | 3 | MOV | DPTR, #immed |
| 91 | 2 | ACALL | addr11 |
| 92 | 2 | MOV | bit, C |
| 93 | 1 | MOVC | A, @A+DPTR |
| 94 | 2 | SUBB | A, #immed |
| 95 | 2 | SUBB | A, direct |
| 96 | 1 | SUBB | A, @R0 |
| 97 | 1 | SUBB | A, @R1 |
| 98 | 1 | SUBB | A, R0 |
| 99 | 1 | SUBB | A, R1 |
| 9A | 1 | SUBB | A, R2 |
| 9B | 1 | SUBB | A, R3 |
| 9C | 1 | SUBB | A, R4 |
| 9D | 1 | SUBB | A, R5 |
| 9E | 1 | SUBB | A, R6 |
| 9F | 1 | SUBB | A, R7 |
| A0 | 2 | ORL | C, /bit |
| A1 | 2 | AJMP | addr11 |
| A2 | 2 | MOV | C, bit |
| A3 | 1 | INC | DPTR |
| A4 | 1 | MUL | AB |
| A5 | reserved | ||
| A6 | 2 | MOV | @R0, direct |
| A7 | 2 | MOV | @R1, direct |
| A8 | 2 | MOV | R0, direct |
| A9 | 2 | MOV | R1, direct |
| AA | 2 | MOV | R2, direct |
| AB | 2 | MOV | R3, direct |
| AC | 2 | MOV | R4, direct |
| AD | 2 | MOV | R5, direct |
| AE | 2 | MOV | R6, direct |
| AF | 2 | MOV | R7, direct |
| B0 | 2 | ANL | C, /bit |
| B1 | 2 | ACALL | addr11 |
| B2 | 2 | CPL | bit |
| B3 | 1 | CPL | C |
| B4 | 3 | CJNE | A, #immed, offset |
| B5 | 3 | CJNE | A, direct, offset |
| B6 | 3 | CJNE | @R0, #immed, offset |
| B7 | 3 | CJNE | @R1, #immed, offset |
| B8 | 3 | CJNE | R0, #immed, offset |
| B9 | 3 | CJNE | R1, #immed, offset |
| BA | 3 | CJNE | R2, #immed, offset |
| BB | 3 | CJNE | R3, #immed, offset |
| BC | 3 | CJNE | R4, #immed, offset |
| BD | 3 | CJNE | R5, #immed, offset |
| BE | 3 | CJNE | R6, #immed, offset |
| BF | 3 | CJNE | R7, #immed, offset |
| C0 | 2 | PUSH | direct |
| C1 | 2 | AJMP | addr11 |
| C2 | 2 | CLR | bit |
| C3 | 1 | CLR | C |
| C4 | 1 | SWAP | A |
| C5 | 2 | XCH | A, direct |
| C6 | 1 | XCH | A, @R0 |
| C7 | 1 | XCH | A, @R1 |
| C8 | 1 | XCH | A, R0 |
| C9 | 1 | XCH | A, R1 |
| CA | 1 | XCH | A, R2 |
| CB | 1 | XCH | A, R3 |
| CC | 1 | XCH | A, R4 |
| CD | 1 | XCH | A, R5 |
| CE | 1 | XCH | A, R6 |
| CF | 1 | XCH | A, R7 |
| D0 | 2 | POP | direct |
| D1 | 2 | ACALL | addr11 |
| D2 | 2 | SETB | bit |
| D3 | 1 | SETB | C |
| D4 | 1 | DA | A |
| D5 | 3 | DJNZ | direct, offset |
| D6 | 1 | XCHD | A, @R0 |
| D7 | 1 | XCHD | A, @R1 |
| D8 | 2 | DJNZ | R0, offset |
| D9 | 2 | DJNZ | R1, offset |
| DA | 2 | DJNZ | R2, offset |
| DB | 2 | DJNZ | R3, offset |
| DC | 2 | DJNZ | R4, offset |
| DD | 2 | DJNZ | R5, offset |
| DE | 2 | DJNZ | R6, offset |
| DF | 2 | DJNZ | R7, offset |
| E0 | 1 | MOVX | A, @DPTR |
| E1 | 2 | AJMP | addr11 |
| E2 | 1 | MOVX | A, @R0 |
| E3 | 1 | MOVX | A, @R1 |
| E4 | 1 | CLR | A |
| E5 | 2 | MOV | A, direct |
| E6 | 1 | MOV | A, @R0 |
| E7 | 1 | MOV | A, @R1 |
| E8 | 1 | MOV | A, R0 |
| E9 | 1 | MOV | A, R1 |
| EA | 1 | MOV | A, R2 |
| EB | 1 | MOV | A, R3 |
| EC | 1 | MOV | A, R4 |
| ED | 1 | MOV | A, R5 |
| EE | 1 | MOV | A, R6 |
| EF | 1 | MOV | A, R7 |
| F0 | 1 | MOVX | @DPTR, A |
| F1 | 2 | ACALL | addr11 |
| F2 | 1 | MOVX | @R0, A |
| F3 | 1 | MOVX | @R1, A |
| F4 | 1 | CPL | A |
| F5 | 2 | MOV | direct, A |
| F6 | 1 | MOV | @R0, A |
| F7 | 1 | MOV | @R1, A |
| F8 | 1 | MOV | R0, A |
| F9 | 1 | MOV | R1, A |
| FA | 1 | MOV | R2, A |
| FB | 1 | MOV | R3, A |
| FC | 1 | MOV | R4, A |
| FD | 1 | MOV | R5, A |
| FE | 1 | MOV | R6, A |
| FF | 1 | MOV | R7, A |
