gpt4 book ai didi

c - 在编译期间将展开的宏打印到文件

转载 作者:行者123 更新时间:2023-12-05 01:39:54 25 4
gpt4 key购买 nike

我想在 gcc 编译器的编译时将宏的结果打印到文件中。我想知道这是否可能。示例如下:

#define MD_BTLDB_APP_VERSION_OFFSET(x) 

扩展为

(0x00000000u + (0x00040000u - ((uint32)(x) * 0x00000100u) - (64u)))

计算到

0x0003ffd6

对于

MD_BTLDB_APP_VERSION_OFFSET(0)

这是引导加载程序的一些元数据的地址,我希望能够在运行时之外使用这个地址。

我查看了#pragma 消息,但这只将值输出到 gcc 输出,而不是文件。它还会带来许多其他编译器消息混合的不便。欢迎任何提示或创造性的解决方案。

最佳答案

我看不出你是怎么得到0x0003ffd6的,因为我得到了0x3ffc0。随便。

在这里,我将描述三种获取扩展宏评估结果的不同方法。

1。 #pragma message 方法。

首先,让我们学习如何扩展宏。这是通过双扫描完成的,您可以在 C Preprocessor tricks, tips, and idioms 阅读更多信息。 .

假设我们有文件 expand.c:

#include <stdio.h>
#include <stdint.h>
typedef uint32_t uint32;

#define MD_BTLDB_APP_VERSION_OFFSET(x)\
(0x00000000u + (0x00040000u - ((uint32)(x) * 0x00000100u) - (64u)))

#define STR(...) STR_(__VA_ARGS__)
#define STR_(...) # __VA_ARGS__

#pragma message "Value of MD_BTLDB_APP_VERSION_OFFSET(0) is " \
STR(MD_BTLDB_APP_VERSION_OFFSET(0))

int main() {
printf("%d\n", MD_BTLDB_APP_VERSION_OFFSET(0));
}

编译完成后,您将拥有一个完整的宏扩展。您可以使用 tee 将其复制到文件中:

$ gcc expand.c 2>&1 | tee output
expand.c:11:9: note: #pragma message: Value of MD_BTLDB_APP_VERSION_OFFSET(0) is (0x00000000u + (0x00040000u - ((uint32)(0) * 0x00000100u) - (64u)))
11 | #pragma message "Value of MD_BTLDB_APP_VERSION_OFFSET(0) is " \
| ^~~~~~~

其次,我们需要抓出表情。我将使用 sed 来完成:

$ pattern='.*note: \#pragma message: Value of MD_BTLDB_APP_VERSION_OFFSET\(0\) is'
$ sed -E -ne "s/$pattern (.*)/\1/p" output
(0 + 0x00000000u + (0x00040000u - ((uint32)(0) * 0x00000100u) - (64u)))

-n 抑制默认输出,表达式末尾的 p 仅打印出匹配的字符串。

最后,计算表达式。我会用 python 或直接用 bash 来做,因为它们都支持十六进制数字。但无论如何,首先我们需要去除 (uint32) 转换和 u suffices 特定于 C 和 C++:

$ expr=$(sed -E -e 's/\(uint32\)//g' \
-e 's/([0-9a-f]+)u/\1/g' \
-ne "s/$pattern (.*)/\1/p" output)
$ printf "0x%016x\n" $(($expr))
0x000000000003ffc0

就是这样!

2。使用主机编译器进行评估。

另一种方法是先获取交叉编译器gcc -E的输出,例如

$ CC_CROSS=arm-noeabi-gcc
$ expr=$($CC_CROSS -E -xc - <<EOF
#include "your_header.h"
MD_BTLDB_APP_VERSION_OFFSET(0)
EOF | tail -n 1)

然后用主机编译器计算表达式:

$ gcc -o get_md_btldb -xc - <<EOF
#include <stdio.h>
int main(){ printf("%p", $expr); }
EOF
$ ./get_md_btldb

应该也可以,但没有尝试过。

3。直接从二进制中取出值!

让我们在您的翻译单元 value.c 中放置一个常量:

typedef uint32_t uint32;

#define MD_BTLDB_APP_VERSION_OFFSET(x) \
(0x00000000u + (0x00040000u - ((uint32)(x) * 0x00000100u) - (64u)))

uintptr_t MD_BTLDB_APP_VERSION_OFFSET_VALUE = MD_BTLDB_APP_VERSION_OFFSET(0);

现在如果你把它编译成一个目标文件,你会在那里有一个符号:

$ gcc -c value.c
$ objdump -t -s -j.data value.o

value.o: file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 g O .data 0000000000000008 MD_BTLDB_APP_VERSION_OFFSET_VALUE


Contents of section .data:
0000 c0ff0300 00000000 ........

就是这样,c0ff0300 00000000,以小端格式编写。和线

0000000000000000 g     O .data  0000000000000008 MD_BTLDB_APP_VERSION_OFFSET_VALUE

表示符号 MD_BTLDB_APP_VERSION_OFFSET_VALUE 的值位于 .data 部分中的偏移量 0 处,大小为 8。您现在可以在那里使用它。

但是看反汇编更容易:

$ gcc -S value.s
$ cat value.s
.file "value.c"
.text
.globl MD_BTLDB_APP_VERSION_OFFSET_VALUE
.data
.align 8
.type MD_BTLDB_APP_VERSION_OFFSET_VALUE, @object
.size MD_BTLDB_APP_VERSION_OFFSET_VALUE, 8
MD_BTLDB_APP_VERSION_OFFSET_VALUE:
.quad 262080
.ident "GCC: (GNU) 9.1.0"
.section .note.GNU-stack,"",@progbits

该值紧跟在 MD_BTLDB_APP_VERSION_OFFSET_VALUE 标签之后:

MD_BTLDB_APP_VERSION_OFFSET_VALUE:
.quad 262080

接受它:

grep -A 1 -e 'MD_BTLDB_APP_VERSION_OFFSET_VALUE:' value.s\
| tail -n 1 | awk '{print $2;}'
| xargs printf "%016x"

000000000003ffc0

关于c - 在编译期间将展开的宏打印到文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57503077/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com