我正在努力了解事物存储在内存中的位置,如全局变量和静态变量(.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文件。这个经过预处理的文件将在实际编译中使用。
您的预处理示例
- 如果
newVariable
具有静态或线程存储持续时间,则在调用main
函数之前将其初始化为该值 - 如果CCD_ 11具有自动存储持续时间,则在调用函数时将其初始化为该值
无论在哪里使用宏,编译器都会获取值100
。它很可能出现在各种机器代码指令中,使用立即模式寻址,例如在表达式语句中使用时,如a = a + 100
或f(100)
。
编译器很可能会根据需要在上述计算表达式所涉及的指令中嵌入这样的小常量,因此,如果我们执行a = a + thisInteger;
和f(thisInteger)
,可能会有两个不同的机器代码指令将常量100
作为立即数嵌入,每个指令一个 全局数据需要处理工作,而不是嵌入小的即时性,因此编译器不会试图在两个用途之间共享100
作为全局或静态数据。
因此,是的,您可以在objdump中看到100
,但对于许多用途,您可能需要查看代码(.text
)部分,以找到使用#100
作为立即数操作数的指令(如果以十六进制打印,则为#64h
) 在反汇编中,您要查找类似add [rbp+24], #100
或move 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在最终输出中是可见的,但它取决于您如何使用它,以及它是如何表示或存储在哪里的。