二进制AND(&)的操作数无效

时间:2013-08-28 18:39:25

标签: gcc assembly ld gas

我有这个“汇编”文件(仅包含directives

// declare protected region as somewhere within the stack
.equiv prot_start, $stack_top & 0xFFFFFF00 - 0x1400
.equiv prot_end,   $stack_top & 0xFFFFFF00 - 0x0C00

结合此链接描述文件:

SECTIONS {
   "$stack_top"   = 0x10000;
}

汇编产生此输出

file.s: Assembler messages:
file.s: Error: invalid operands (*UND* and *ABS* sections) for `&' when setting `prot_start'
file.s: Error: invalid operands (*UND* and *ABS* sections) for `&' when setting `prot_end'

我该如何做到这一点?

2 个答案:

答案 0 :(得分:3)

为什么不可能?

您已与GAS文档相关联,但无效的理由是什么?

答案:GAS必须通过ELF目标文件向链接器传达操作,唯一可以传达的事情是+--只是{{} 1}}负值)。所以这是ELF格式的基本限制,而不仅仅是GAS开发人员的懒惰。

当GAS编译到目标文件时,将跟随一个链接步骤,它将是重定位,它将决定符号的最终值。

问题:为什么+可以传达,而不是+

答案:因为&具有传递性:+(a + b) + c == a + (b + c)+不是“一起传递”:&

让我们看看(a & b) + c!= a & (b + c)如何通过ELF格式传达,以说服自己+是不可能的。

如果您不熟悉,请先了解重新定位的内容:https://stackoverflow.com/a/30507725/895245

让我们用另一个产生相同错误的例子来最小化你的例子:

&

编译和反编译:

a: .long s
b: .long s + 0x12345678
/* c: .long s & 1 */
s:

输出包含:

as --32 -o main.o main.S
objdump -dzr main.o

忽略反汇编,因为这不是代码,只看符号,字节和重定位。

我们有两次00000000 <a>: 0: 08 00 or %al,(%eax) 0: R_386_32 .text 2: 00 00 add %al,(%eax) 00000004 <b>: 4: 80 56 34 12 adcb $0x12,0x34(%esi) 4: R_386_32 .text 次搬迁。从用于IA-32的System V ABI(定义ELF格式),该类型的重定位计算如下:

R_386_32

其中:

  • S + A :目标文件中重定位前的值

    在重定位之前S的值= a == 08 00 00 00在小端

    重定位前8的值= b == 80 56 34 12小端

  • 0x12345680:addend,重新分配条目的字段,此处A0未显示),所以让我们忘掉它。

    < / LI>

重新安置时:

  • objdump将替换为:

    a

    address of text section + 8 因为+ 8是文本部分的第8个字节,前面有2个长。

  • s:将替换为:

    b

    啊哈,这就是 address of text section + (0x12345678 + 8) == address of text section + 0x12345680 出现在目标文件上的原因!

正如我们刚刚看到的那样,只需添加到实际偏移量就可以在ELF文件上表达0x12345680

但是不可能用这种机制(或我所知道的任何其他机制)来表达+,因为我们不知道重定位后文本部分的地址是什么,所以我们不能将&应用于此。

答案 1 :(得分:1)

织补:

  

Infix Operators

     

中缀运营商采用两个参数,一个在两边。运算符具有优先权,但具有相同优先级的运算从左到右执行。 除了+-之外,两个参数都必须是绝对的,结果是绝对的。