jli*_*u83 3 c macros gcc compilation
我想在 gcc 编译器编译时将宏的结果打印到文件中。我想知道这是否可能。下面的例子:
#define MD_BTLDB_APP_VERSION_OFFSET(x)
Run Code Online (Sandbox Code Playgroud)
扩展到
(0x00000000u + (0x00040000u - ((uint32)(x) * 0x00000100u) - (64u)))
Run Code Online (Sandbox Code Playgroud)
计算得出
0x0003ffd6
Run Code Online (Sandbox Code Playgroud)
为了
MD_BTLDB_APP_VERSION_OFFSET(0)
Run Code Online (Sandbox Code Playgroud)
这是引导加载程序的一些元数据的地址,我希望能够在运行时之外使用该地址。
我查看了 #pragma 消息,但这仅将值输出到 gcc 输出,而不是输出到文件。它还存在混入许多其他编译器消息的不便。欢迎任何提示或创造性的解决方案。
我不知道你是怎么得到的0x0003ffd6,因为我得到了0x3ffc0。任何。
在这里,我将描述获得扩展宏观评估结果的三种不同方法。
#pragma message方法。首先,我们来学习一下如何扩展宏。这是通过双重扫描完成的,您可以在C 预处理器技巧、提示和习惯用法中阅读更多相关信息。
假设我们有文件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));
}
Run Code Online (Sandbox Code Playgroud)
编译后,您将获得宏的完整扩展。您可以使用 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 " \
| ^~~~~~~
Run Code Online (Sandbox Code Playgroud)
其次,我们需要抓住表达方式。我将使用 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)))
Run Code Online (Sandbox Code Playgroud)
-n抑制默认输出并p在表达式末尾仅打印出匹配的字符串。
最后,评估表达式。我会使用 python 或直接使用 bash 来完成此操作,因为它们都支持十六进制数字。但无论如何,首先我们需要删除特定于 C 和 C++ 的(uint32)转换和suffices:u
$ 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
Run Code Online (Sandbox Code Playgroud)
就是这样!
另一种方法是首先获得交叉编译器的输出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)
Run Code Online (Sandbox Code Playgroud)
然后使用主机编译器评估表达式:
$ gcc -o get_md_btldb -xc - <<EOF
#include <stdio.h>
int main(){ printf("%p", $expr); }
EOF
$ ./get_md_btldb
Run Code Online (Sandbox Code Playgroud)
应该也可以,但没有尝试。
让我们在翻译单元中添加一个常量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);
Run Code Online (Sandbox Code Playgroud)
现在,如果将其编译为目标文件,其中将有一个符号:
$ 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 ........
Run Code Online (Sandbox Code Playgroud)
就是这样,c0ff0300 00000000以小端格式编写。还有那条线
0000000000000000 g O .data 0000000000000008 MD_BTLDB_APP_VERSION_OFFSET_VALUE
Run Code Online (Sandbox Code Playgroud)
意味着符号MD_BTLDB_APP_VERSION_OFFSET_VALUE的值位于该部分中的偏移量 0 处.data并且大小为 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
Run Code Online (Sandbox Code Playgroud)
该值就在MD_BTLDB_APP_VERSION_OFFSET_VALUE标签后面:
MD_BTLDB_APP_VERSION_OFFSET_VALUE:
.quad 262080
Run Code Online (Sandbox Code Playgroud)
拿去:
grep -A 1 -e 'MD_BTLDB_APP_VERSION_OFFSET_VALUE:' value.s\
| tail -n 1 | awk '{print $2;}'
| xargs printf "%016x"
000000000003ffc0
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2265 次 |
| 最近记录: |