Waq*_*med 6 c++ assembly gcc clang compiler-explorer
我想在本地生成像编译器资源管理器这样的干净程序集。请注意,我阅读了如何从 GCC/clang 程序集输出中删除“噪音”?在尝试之前。与 Godbolt 相比,使用该方法的输出没有那么干净或密集,并且仍然有很多 asm 指令和未使用的标签。
如何在没有任何未使用的标签或指令的情况下获得干净的汇编输出?
作为记录,可以(而且显然不太难)设置本地安装 Matt Godbolt 的 Compiler Explorer 内容,因此您可以使用它来探索作为现有大型项目一部分的文件的 asm 输出及其#include依赖项和所有内容.
如果您已经有一些 asm 输出,@Waqar 的回答看起来很有用。或者,也许可以通过 node.js、IDK 从 Compiler Explorer 存储库单独使用该功能。
根据https://github.com/compiler-explorer/compiler-explorer(Matt的 repo)自述文件中的安装信息,您可以make在安装了 node.js 的机器上克隆它后简单地运行。
我还发现https://isocpp.org/blog/2017/10/cpp-weekly-episode-83-installing-compiler-explorerjason-turner可能有更多细节(或者在这一点上已经过时,IDK)。
我认为 Matt 在他的 CppCon 2017 演讲中也提到了使用 Compiler Explorer 的本地克隆(可能在最后回答了一个问题),“我的编译器最近为我做了什么?Unbolting the Compiler's Lid ”,并推荐使用它来处理使用大量代码的代码,这些代码#include很难进入https://godbolt.org/。(或用于封闭源代码)。
不久前,我在本地需要这样的东西,所以我写了一个小工具来使 asm 可读。
它尝试使用 C++ 本身“清理”并使“gcc”的“asm”输出可读。它执行类似于Compiler Explorer 的操作,并尝试删除所有指令和未使用的标签,从而使 asm 干净。仅使用标准库。
我应该提到的一些事情:
-S -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm -masm=intel,编译(-masm=如果你想要 AT&T asm ,请删除) AT&T 语法可能会起作用,但我没有对其进行太多测试。另外两个选项是删除.cfi指令。可以使用下面的代码处理它,但编译器本身在这方面做得更好。请参阅上面Peter Cordes 的回答。abi::__cxa_demangle() 用于拆线用于清理 asm 的策略(可能有更好、更快、更有效的方法来做到这一点):
更新 1:现在并非所有静态数据都被删除。
#include <algorithm>
#include <cxxabi.h>
#include <fstream>
#include <iostream>
#include <regex>
#include <string>
#include <sstream>
#include <unordered_map>
// trim from both ends (in place)
std::string_view trim(std::string_view s)
{
s.remove_prefix(std::min(s.find_first_not_of(" \t\r\v\n"), s.size()));
s.remove_suffix(std::min(s.size() - s.find_last_not_of(" \t\r\v\n") - 1, s.size()));
return s;
}
static inline bool startsWith(const std::string_view s, const std::string_view searchString)
{
return (s.rfind(searchString, 0) == 0);
}
std::string demangle(std::string &&asmText)
{
int next = 0;
int last = 0;
while (next != -1) {
next = asmText.find("_Z", last);
//get token
if (next != -1) {
int tokenEnd = asmText.find_first_of(":,.@[]() \n", next + 1);
int len = tokenEnd - next;
std::string tok = asmText.substr(next, len);
int status = 0;
char* name = abi::__cxa_demangle(tok.c_str(), 0, 0, &status);
if (status != 0) {
std::cout << "Demangling of: " << tok << " failed, status: " << status << '\n';
continue;
}
std::string demangledName{name};
demangledName.insert(demangledName.begin(), ' ');
asmText.replace(next, len, demangledName);
free((void*)name);
}
}
return std::move(asmText);
}
std::string clean_asm(const std::string& asmText)
{
std::string output;
output.reserve(asmText.length());
std::stringstream s{asmText};
//1. collect all the labels
//2. go through the asm line by line and check if the labels are used/unused
//3. if the labels are unused, they get deleted
//4. every line beginning with '.' gets deleted, unless it is a used label
std::regex exp {"^\\s*[_|a-zA-Z]"};
std::regex directiveRe { "^\\s*\\..*$" };
std::regex labelRe { "^\\.*[a-zA-Z]+[0-9]+:$" };
std::regex hasOpcodeRe { "^\\s*[a-zA-Z]" };
std::regex numericLabelsRe { "\\s*[0-9]:" };
const std::vector<std::string> allowedDirectives =
{
".string", ".zero", ".byte", ".value", ".long", ".quad", ".ascii"
};
//<label, used>
std::unordered_map<std::string, bool> labels;
//1
std::string line;
while (std::getline(s, line)) {
if (std::regex_match(line, labelRe)) {
trim(line);
// remove ':'
line = line.substr(0, line.size() - 1);
labels[line] = false;
}
}
s.clear();
s.str(asmText);
line = "";
//2
while (std::getline(s, line)) {
if (std::regex_match(line, hasOpcodeRe)) {
auto it = labels.begin();
for (; it != labels.end(); ++it) {
if (line.find(it->first)) {
labels[it->first] = true;
}
}
}
}
//remove false labels from labels hash-map
for (auto it = labels.begin(); it != labels.end();) {
if (it->second == false)
it = labels.erase(it);
else
++it;
}
s.clear();
s.str(asmText);
line = "";
std::string currentLabel;
//3
while (std::getline(s, line)) {
trim(line);
if (std::regex_match(line, labelRe)) {
auto l = line;
l = l.substr(0, l.size() - 1);
currentLabel = "";
if (labels.find(l) != labels.end()) {
currentLabel = line;
output += line + "\n";
}
continue;
}
if (std::regex_match(line, directiveRe)) {
//if we are in a label
if (!currentLabel.empty()) {
auto trimmedLine = trim(line);
for (const auto& allowedDir : allowedDirectives) {
if (startsWith(trimmedLine, allowedDir)) {
output += line;
output += '\n';
}
}
}
continue;
}
if (std::regex_match(line, numericLabelsRe)) {
continue;
}
if (line == "endbr64") {
continue;
}
if (line[line.size() - 1] == ':' || line.find(':') != std::string::npos) {
currentLabel = line;
output += line + '\n';
continue;
}
line.insert(line.begin(), '\t');
output += line + '\n';
}
return output;
}
int main(int argc, char* argv[])
{
if (argc < 2) {
std::cout << "Please provide more than asm filename you want to process.\n";
}
std::ifstream file(argv[1]);
std::string output;
if (file.is_open()) {
std::cout << "File '" << argv[1] << "' is opened\n";
std::string line;
while (std::getline(file, line)) {
output += line + '\n';
}
}
output = demangle(std::move(output));
output = clean_asm(output);
std::string fileName = argv[1];
auto dotPos = fileName.rfind('.');
if (dotPos != std::string::npos)
fileName.erase(fileName.begin() + dotPos, fileName.end());
std::cout << "Asm processed. Saving as '"<< fileName <<".asm'";
std::ofstream out;
out.open(fileName + ".asm");
out << output;
return 0;
}
Run Code Online (Sandbox Code Playgroud)