c-诸如全局整数之类的宏存储在内存中的位置



我正在努力了解事物存储在内存中的位置,如全局变量和静态变量(.data,如果未初始化为零)等。

我试图找到/考虑的是如下所示的宏:

#define thisInteger 100

这可以使用objdump找到吗?

此外,如果我把它分配给一个新的变量,比如下面,在哪里可以找到它(在.data中猜测):

#define THIS_INTEGER 100
int newVariable = THIS_INTEGER;

宏不是变量,因此它们不会存储在任何地方。当执行#define thisInteger 100时,C预处理器会运行源代码,并用整数文本100替换thisInteger。询问thisInteger存储在哪里与询问100存储在哪里相同。要验证这一点,请尝试类似&thisInteger的方法。它不会编译,因为&100是非法的,没有任何意义。

这可以使用objdump找到吗?

否。预处理是在编译之前进行的复制粘贴处理。

此外,如果我将其分配给一个新变量,如下面所示,在哪里可以找到

取决于定义变量的位置。

宏仅在编译时(编译前进行预处理)

如果您使用gcc编译器,您可以通过使用-E gcc选项来查看经过预处理的C文件。这个经过预处理的文件将在实际编译中使用。

您的预处理示例

  1. 如果newVariable具有静态或线程存储持续时间,则在调用main函数之前将其初始化为该值
  2. 如果CCD_ 11具有自动存储持续时间,则在调用函数时将其初始化为该值

无论在哪里使用宏,编译器都会获取值100。它很可能出现在各种机器代码指令中,使用立即模式寻址,例如在表达式语句中使用时,如a = a + 100f(100)

编译器很可能会根据需要在上述计算表达式所涉及的指令中嵌入这样的小常量,因此,如果我们执行a = a + thisInteger;f(thisInteger),可能会有两个不同的机器代码指令将常量100作为立即数嵌入,每个指令一个 全局数据需要处理工作,而不是嵌入小的即时性,因此编译器不会试图在两个用途之间共享100作为全局或静态数据。

因此,是的,您可以在objdump中看到100,但对于许多用途,您可能需要查看代码(.text)部分,以找到使用#100作为立即数操作数的指令(如果以十六进制打印,则为#64h) 在反汇编中,您要查找类似add [rbp+24], #100move rdi, #100的说明。

您是对的,如果您声明一个可变全局变量int x = thisInteger;,您可以在带有objdump的数据(.data)部分中找到100 但相同声明的局部变量将在运行时使用机器代码指令进行初始化,因此类似于mov ??, #100

自己试试看

起点:so.c

#define THIS_INTEGER 100
int newVariable = THIS_INTEGER;
void fun0 ( void )
{
static int hello;
hello = 100;
}
int fun1 ( void )
{
int hello;
hello = 100;
return(hello);
}

预处理器对定义的进行搜索和替换

arm-none-eabi-gcc -save-temps -O2 -c so.c -o so.o

so.i

# 1 "so.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "so.c"

int newVariable = 100;
void fun0 ( void )
{
static int hello;
hello = 100;
}
int fun1 ( void )
{
int hello;
hello = 100;
return(hello);
}

你可以看到THIS_INTEGER已经不存在了——它只是一个宏/定义。在这种情况下,它的目的是保留常量的一部分,这样,如果你想更改它,你就可以更改它的所有相关实例。但编译器需要一些它可以实际编译的东西。

预处理器输出的so.i然后被提供给实际的编译器,从而产生汇编:so.s

.cpu arm7tdmi
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 1
.eabi_attribute 30, 2
.eabi_attribute 34, 0
.eabi_attribute 18, 4
.file   "so.c"
.text
.align  2
.global fun0
.arch armv4t
.syntax unified
.arm
.fpu softvfp
.type   fun0, %function
fun0:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
bx  lr
.size   fun0, .-fun0
.align  2
.global fun1
.syntax unified
.arm
.fpu softvfp
.type   fun1, %function
fun1:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
mov r0, #100
bx  lr
.size   fun1, .-fun1
.global newVariable
.data
.align  2
.type   newVariable, %object
.size   newVariable, 4
newVariable:
.word   100
.ident  "GCC: (GNU) 9.2.0"

它被提供给汇编程序,然后如果你分解它,你会得到:

Disassembly of section .text:
00000000 <fun0>:
0:   e12fff1e    bx  lr
00000004 <fun1>:
4:   e3a00064    mov r0, #100    ; 0x64
8:   e12fff1e    bx  lr
Disassembly of section .data:
00000000 <newVariable>:
0:   00000064 

呃,我本来希望静电能把它保持在那里。对于正在初始化的全局变量,如果不是.data,它将是.bss。然后在.data中可以看到100(0x64)。但它与宏无关/定义宏/定义只是将实际值100放入实际编译的代码中。

对于另一种情况,在这里进行优化时,堆栈上没有变量或类似的东西,值被放置在返回寄存器中,因此在这种情况下,它短暂地存在于寄存器中。

如果静态效果如所愿,事后看来,这是有道理的,但没有。我希望有一个我称之为本地全球化的东西。它是一个局部变量,但添加static会将它放在.bss或.data中,而不是堆栈中,然后希望看到生成的代码,然后将100放在变量中,然后将其放在.data/.bss区域中,这当然是未优化的,但更难读取:

Disassembly of section .text:
00000000 <fun0>:
0:   e52db004    push    {r11}       ; (str r11, [sp, #-4]!)
4:   e28db000    add r11, sp, #0
8:   e59f3018    ldr r3, [pc, #24]   ; 28 <fun0+0x28>
c:   e3a02064    mov r2, #100    ; 0x64
10:   e5832000    str r2, [r3]
14:   e1a00000    nop         ; (mov r0, r0)
18:   e1a00003    mov r0, r3
1c:   e28bd000    add sp, r11, #0
20:   e49db004    pop {r11}       ; (ldr r11, [sp], #4)
24:   e12fff1e    bx  lr
28:   00000000    andeq   r0, r0, r0
0000002c <fun1>:
2c:   e52db004    push    {r11}       ; (str r11, [sp, #-4]!)
30:   e28db000    add r11, sp, #0
34:   e24dd00c    sub sp, sp, #12
38:   e3a03064    mov r3, #100    ; 0x64
3c:   e50b3008    str r3, [r11, #-8]
40:   e51b3008    ldr r3, [r11, #-8]
44:   e1a00003    mov r0, r3
48:   e28bd000    add sp, r11, #0
4c:   e49db004    pop {r11}       ; (ldr r11, [sp], #4)
50:   e12fff1e    bx  lr
Disassembly of section .data:
00000000 <newVariable>:
0:   00000064    andeq   r0, r0, r4, rrx
Disassembly of section .bss:
00000000 <hello.4142>:
0:   00000000    andeq   r0, r0, r0

具体而言:

c:   e3a02064    mov r2, #100    ; 0x64
10:   e5832000    str r2, [r3]

100被放入一个寄存器中,然后该寄存器值被写入内存,来自fun0的本地全局hello位于.bss.中

宏/定义简单地搜索和替换,预处理器将根据需要对不同级别/层的宏进行多次迭代,直到它们都被替换掉,没有一个像预处理代码中所写的那样存在。然后将其发送到编译器。

在这种情况下,VALUE 100在最终输出中是可见的,但它取决于您如何使用它,以及它是如何表示或存储在哪里的。

最新更新