关于汇编中IT条件代码的问题
Questions about IT conditional codes in assembly
大多数示例都有如下 IT 命令,
ITTE NE ; IT can be omitted
ANDNE r0,r0,r1 ; 16-bit AND, not ANDS
ADDSNE r2,r2,#1 ; 32-bit ADDS (16-bit ADDS does not set flags in IT block)
MOVEQ r2,r3 ; 16-bit MOV
ITT AL ; emit 2 non-flag setting 16-bit instructions
ADDAL r0,r0,r1 ; 16-bit ADD, not ADDS
SUBAL r2,r2,#1 ; 16-bit SUB, not SUB
ADD r0,r0,r1 ; expands into 32-bit ADD, and is not in IT block
ITT EQ
MOVEQ r0,r1
BEQ dloop ; branch at end of IT block is permitted
ITT EQ
MOVEQ r0,r1
BKPT #1 ; BKPT always executes
ADDEQ r0,r0,#1
我想查看示例中的最后一个 IT 块。
我真的很困惑发生了什么。对于 MOVEQ,我认为它正在检查 r0 = r1,如果它们相等,则将 r1 移动到 r0。但如果它们相等,那没有意义。究竟是怎么回事?
我写了一个拇指代码来检查哪个数字更大:
cmp r0, r1
ITE HS
movhs r0, r0
movlo r0, r1
这里我需要比较 IT 块之前的寄存器...
但是为什么所有的例子都不包括至少在手前的比较呢?是否有另一种方法可以为我的示例编写不包含比较的 IT 块?这些示例中到底发生了什么?
标志是 IT 块内谓词指令的输入。是的,您确实在 it
之前的某个点放置了 cmp
或 adds
或任何其他标志设置指令。以前不一定对
您展示的示例用于记录 IT
的极端情况,而不是 full/complete 使用它实际执行特定操作的示例。
条件分支指令的文档通常也不显示标志设置指令。
With the exception of CMP, CMN, and TST, the 16-bit instructions that normally affect the condition code flags, do not affect them when used inside an IT block.
但其中一个示例确实清楚地表明您可以在 IT 块内更改带有 32 位 adds
的标志,这告诉我们允许使用常规 compare/test 指令。
文档没有明确说明在 IT 块中对标志的更改 会影响块内后面的谓词指令。 @DanLewis 的回答证实了他们这样做。
在 ARM 模式下,不需要 IT 块来谓词执行(每条指令中的 4 位编码一个谓词)因此标志设置指令显然会影响后面的指令。它在 Thumb 模式下以相同的方式工作是有道理的,特别是因为 IT
在某些语法中是可选的。 (一些汇编程序会在为 thumb 模式汇编时以统一语法为您插入它。)
@Darklink9110: yes, you can change flags inside an IT block, the docs are clear on that. > They're not clear on whether that has any effect on the rest of the current block.
我在 ARM Cortex-M4 (Thumb-2) 上测试了以下两个函数以找出答案,事实证明,如果 IT 块内的指令更改标志,则同一 IT 块中的后续指令(1) ADC、SBC、RRX 等确实使用了新的标志值,并且 (2) 可能会根据新的标志值更改其 enabled/disabled 状态。
// Inside an IT block, do instructions that use the carry flag (e.g., ADC) see
// changes to the carry flag caused by previous instructions in the same IT block?
Test1: MOV R0,1 // R0 = 1
CMP R0,R0 // C = 0, Z = 1 (EQ)
ITT EQ
LSRSEQ R0,R0,1 // C = 1, Z = 1 (EQ), R0 = 0
ADCEQ R0,R0,0 // R0 = R0 + C
BX LR // **Returns 1 in R0**
// Do flags that are changed by instruction in an IT block update which
// subsequent instructions in the same IT block are enabled/disabled?
Test2: MOV R0,1 // R0 = 1
CMP R0,R0 // Z = 1 (EQ)
ITT EQ
CMPEQ R0,0 // Z = 0 (NE)
MOVEQ R0,0 // R0 = 0 ? (Disabled!)
BX LR // **Returns 1 in R0**
大多数示例都有如下 IT 命令,
ITTE NE ; IT can be omitted
ANDNE r0,r0,r1 ; 16-bit AND, not ANDS
ADDSNE r2,r2,#1 ; 32-bit ADDS (16-bit ADDS does not set flags in IT block)
MOVEQ r2,r3 ; 16-bit MOV
ITT AL ; emit 2 non-flag setting 16-bit instructions
ADDAL r0,r0,r1 ; 16-bit ADD, not ADDS
SUBAL r2,r2,#1 ; 16-bit SUB, not SUB
ADD r0,r0,r1 ; expands into 32-bit ADD, and is not in IT block
ITT EQ
MOVEQ r0,r1
BEQ dloop ; branch at end of IT block is permitted
ITT EQ
MOVEQ r0,r1
BKPT #1 ; BKPT always executes
ADDEQ r0,r0,#1
我想查看示例中的最后一个 IT 块。 我真的很困惑发生了什么。对于 MOVEQ,我认为它正在检查 r0 = r1,如果它们相等,则将 r1 移动到 r0。但如果它们相等,那没有意义。究竟是怎么回事?
我写了一个拇指代码来检查哪个数字更大:
cmp r0, r1
ITE HS
movhs r0, r0
movlo r0, r1
这里我需要比较 IT 块之前的寄存器... 但是为什么所有的例子都不包括至少在手前的比较呢?是否有另一种方法可以为我的示例编写不包含比较的 IT 块?这些示例中到底发生了什么?
标志是 IT 块内谓词指令的输入。是的,您确实在 it
之前的某个点放置了 cmp
或 adds
或任何其他标志设置指令。以前不一定对
您展示的示例用于记录 IT
的极端情况,而不是 full/complete 使用它实际执行特定操作的示例。
条件分支指令的文档通常也不显示标志设置指令。
With the exception of CMP, CMN, and TST, the 16-bit instructions that normally affect the condition code flags, do not affect them when used inside an IT block.
但其中一个示例确实清楚地表明您可以在 IT 块内更改带有 32 位 adds
的标志,这告诉我们允许使用常规 compare/test 指令。
文档没有明确说明在 IT 块中对标志的更改 会影响块内后面的谓词指令。 @DanLewis 的回答证实了他们这样做。
在 ARM 模式下,不需要 IT 块来谓词执行(每条指令中的 4 位编码一个谓词)因此标志设置指令显然会影响后面的指令。它在 Thumb 模式下以相同的方式工作是有道理的,特别是因为 IT
在某些语法中是可选的。 (一些汇编程序会在为 thumb 模式汇编时以统一语法为您插入它。)
@Darklink9110: yes, you can change flags inside an IT block, the docs are clear on that. > They're not clear on whether that has any effect on the rest of the current block.
我在 ARM Cortex-M4 (Thumb-2) 上测试了以下两个函数以找出答案,事实证明,如果 IT 块内的指令更改标志,则同一 IT 块中的后续指令(1) ADC、SBC、RRX 等确实使用了新的标志值,并且 (2) 可能会根据新的标志值更改其 enabled/disabled 状态。
// Inside an IT block, do instructions that use the carry flag (e.g., ADC) see // changes to the carry flag caused by previous instructions in the same IT block? Test1: MOV R0,1 // R0 = 1 CMP R0,R0 // C = 0, Z = 1 (EQ) ITT EQ LSRSEQ R0,R0,1 // C = 1, Z = 1 (EQ), R0 = 0 ADCEQ R0,R0,0 // R0 = R0 + C BX LR // **Returns 1 in R0** // Do flags that are changed by instruction in an IT block update which // subsequent instructions in the same IT block are enabled/disabled? Test2: MOV R0,1 // R0 = 1 CMP R0,R0 // Z = 1 (EQ) ITT EQ CMPEQ R0,0 // Z = 0 (NE) MOVEQ R0,0 // R0 = 0 ? (Disabled!) BX LR // **Returns 1 in R0**