Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 131 additions & 41 deletions src/cpp/analyzer/transform_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,73 @@ modify_apply_offset_57(char* text_section_data, size_t text_section_size, uint32
}
}

/**
* @brief Modify apply_offset_57 opcodes for merged single-section format.
*
* The merged section contains all pages for a column concatenated. Each page
* occupies exactly PAGE_SIZE bytes with layout:
* [page_header 16B][text instructions][data BDs][zero padding to PAGE_SIZE]
*
* For each page the text portion is identified via cur_page_len stored in the
* page header (bytes 8-9). An apply_offset_57 instruction stores a table_ptr
* field that is relative to its own page's temp encoding (= T_N + D_bd). To
* match the corrected r_offset value written into the ELF relocations we add
* (page_start + elf_section_header_size) before looking up xrt_idx_lookup.
*/
void
transform_manager::
modify_apply_offset_57_merged(char* section_data, size_t section_size, uint32_t section_idx)
{
size_t page_start = 0;
while (page_start + elf_section_header_size <= section_size) {
// Read cur_page_len from page header bytes 8-9 (little-endian)
uint16_t cur_page_len =
static_cast<uint8_t>(section_data[page_start + 8]) |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 8 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

      static_cast<uint8_t>(section_data[page_start + 8]) |
                                                     ^

(static_cast<uint8_t>(section_data[page_start + 9]) << 8);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 8 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

      (static_cast<uint8_t>(section_data[page_start + 9]) << 8);
                                                             ^

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 9 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

      (static_cast<uint8_t>(section_data[page_start + 9]) << 8);
                                                      ^


size_t text_start = page_start + elf_section_header_size;
size_t text_end = page_start + cur_page_len;

if (text_end > section_size || text_end <= text_start) {
page_start += PAGE_SIZE;
continue;
}
Comment on lines +182 to +193
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modify_apply_offset_57_merged() uses cur_page_len from the page header to determine text_end, but cur_page_len is the total page length (header + text + data), not just the text length (see pager calculation: PAGE_HEADER_SIZE + tsize + ... + dsize). This will cause the loop to interpret BD/data bytes as opcodes and likely throw Unknown Opcode or silently skip/patch wrong bytes. Consider determining the end of the text region by disassembling until the EOF instruction (as the disassembler does) and stopping there, rather than using cur_page_len as the text boundary.

Copilot uses AI. Check for mistakes.

for (size_t offset = text_start; offset < text_end;) {
uint8_t opcode = static_cast<uint8_t>(section_data[offset]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: use auto when initializing with a cast to avoid duplicating the type name [hicpp-use-auto]

Suggested change
uint8_t opcode = static_cast<uint8_t>(section_data[offset]);
auto opcode = static_cast<uint8_t>(section_data[offset]);


if (opcode == align_opcode) {
++offset;
continue;
}

auto op_it = isa_op_map->find(opcode);
if (op_it == isa_op_map->end())
throw error(error::error_code::invalid_asm,
"Unknown Opcode:" + std::to_string(opcode) +
" at position " + std::to_string(offset) + "\n");

if (opcode == OPCODE_APPLY_OFFSET_57) {
auto* code = reinterpret_cast<apply_offset_57*>(section_data + offset);
// table_ptr is the BD offset within the temp per-page encoding (T_N + D_bd).
// The relocation r_offset = page_start + elf_section_header_size + table_ptr,
// so adjust table_ptr to build the matching lookup key.
uint32_t adjusted_ptr = static_cast<uint32_t>(code->table_ptr) +
static_cast<uint32_t>(page_start) +
static_cast<uint32_t>(elf_section_header_size);
auto key = get_key(adjusted_ptr, section_idx);
auto lookup_it = xrt_idx_lookup.find(key);
if (lookup_it != xrt_idx_lookup.end())
code->offset = static_cast<uint16_t>(lookup_it->second * num_32bit_register);
}

offset += size(op_it->second);
}

page_start += PAGE_SIZE;
}
}

/**
* @brief Process all text sections and modify apply_offset_57 opcodes
*
Expand All @@ -174,9 +241,12 @@ process_sections() {
const ELFIO::section* section = section_ptr.get();
const auto& section_name = section->get_name();

// Process only .ctrltext sections with PROGBITS type
if (is_text_section(section_name) && section->get_type() == ELFIO::SHT_PROGBITS)
modify_apply_offset_57(const_cast<char *>(section->get_data()), section->get_size(), num);
if (is_text_section(section_name) && section->get_type() == ELFIO::SHT_PROGBITS) {
if (is_merged_section_name(section_name))
modify_apply_offset_57_merged(const_cast<char*>(section->get_data()), section->get_size(), num);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use const_cast to remove const qualifier [cppcoreguidelines-pro-type-const-cast]

        modify_apply_offset_57_merged(const_cast<char*>(section->get_data()), section->get_size(), num);
                                      ^

else
modify_apply_offset_57(const_cast<char*>(section->get_data()), section->get_size(), num);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use const_cast to remove const qualifier [cppcoreguidelines-pro-type-const-cast]

        modify_apply_offset_57(const_cast<char*>(section->get_data()), section->get_size(), num);
                               ^

}

++num;
}
Expand Down Expand Up @@ -438,25 +508,35 @@ uint64_t
transform_manager::
get_controlcode_bd_offset(const std::string& section_name, uint32_t offset, symbol::patch_schema schema)
{
auto [col, page] = get_column_and_page(section_name);
auto id = get_grp_id_if_group_elf(section_name);
auto ctrltext = m_elfio.sections[get_ctrltext_section_name(col, page, id)];
auto ctrldata = m_elfio.sections[get_ctrldata_section_name(col, page, id)];
if (!ctrltext || !ctrldata)
throw error(error::error_code::internal_error, "ctrltext or ctrldata section for col:"
+ std::to_string(col) + " page:" + std::to_string(page) + " not found\n");

if (offset < ctrltext->get_size())
throw error(error::error_code::internal_error, "ctrltext size lesser than offset:"
+ std::to_string(offset) + "\n");

// Adjust offset to point into ctrldata section
offset -= static_cast<uint32_t>(ctrltext->get_size());
offset += elf_section_header_size;

const auto* bd_data_ptr = reinterpret_cast<const uint32_t*>(ctrldata->get_data() + offset);
auto ctrltext = m_elfio.sections[section_name];
if (!ctrltext)
throw error(error::error_code::internal_error, "ctrltext section '" + section_name + "' not found\n");

const uint32_t* bd_data_ptr = nullptr;

if (is_merged_section_name(section_name)) {
// Merged format (.ctrltext.<col>): offset is the absolute byte position of
// the BD within the merged section.
if (offset >= ctrltext->get_size())
throw error(error::error_code::internal_error, "merged ctrltext offset out of range:"
+ std::to_string(offset) + "\n");
bd_data_ptr = reinterpret_cast<const uint32_t*>(ctrltext->get_data() + offset);
} else {
// Per-page format (.ctrltext.<col>.<page>): offset = T_N + D_bd,
// ctrltext size = 16 + T_N. Adjust to index into the paired ctrldata section.
auto [col, page] = get_column_and_page(section_name);
auto id = get_grp_id_if_group_elf(section_name);
auto ctrldata = m_elfio.sections[get_ctrldata_section_name(col, page, id)];
if (!ctrldata)
throw error(error::error_code::internal_error, "ctrldata section for col:"
+ std::to_string(col) + " page:" + std::to_string(page) + " not found\n");
if (offset < ctrltext->get_size())
throw error(error::error_code::internal_error, "ctrltext size lesser than offset:"
+ std::to_string(offset) + "\n");
uint32_t data_offset = offset - static_cast<uint32_t>(ctrltext->get_size()) + elf_section_header_size;
bd_data_ptr = reinterpret_cast<const uint32_t*>(ctrldata->get_data() + data_offset);
}

// Read BD based on schema (AIE2PS vs AIE4)
switch(schema) {
case symbol::patch_schema::shim_dma_57:
return read57(bd_data_ptr);
Expand All @@ -482,27 +562,37 @@ void
transform_manager::
set_controlcode_bd_offset(const std::string& section_name, uint32_t offset, uint64_t bd_offset, symbol::patch_schema schema)
{
auto [col, page] = get_column_and_page(section_name);
auto id = get_grp_id_if_group_elf(section_name);
auto ctrltext = m_elfio.sections[get_ctrltext_section_name(col, page, id)];
auto ctrldata = m_elfio.sections[get_ctrldata_section_name(col, page, id)];
if (!ctrltext || !ctrldata)
throw error(error::error_code::internal_error, "ctrltext or ctrldata section for col:"
+ std::to_string(col) + " page:" + std::to_string(page) + " not found\n");
if (offset < ctrltext->get_size())
throw error(error::error_code::internal_error, "ctrldata size lesser than offset:"
+ std::to_string(offset) + "\n");

// Adjust offset to point into ctrldata section
offset -= static_cast<uint32_t>(ctrltext->get_size());
offset += elf_section_header_size;
if (offset > ctrldata->get_size())
throw error(error::error_code::internal_error, "ctrltext size lesser than offset:"
+ std::to_string(offset) + "\n");

auto* bd_data_ptr = reinterpret_cast<uint32_t*>(const_cast<char*>(ctrldata->get_data()) + offset);
auto ctrltext = m_elfio.sections[section_name];
if (!ctrltext)
throw error(error::error_code::internal_error, "ctrltext section '" + section_name + "' not found\n");

uint32_t* bd_data_ptr = nullptr;

if (is_merged_section_name(section_name)) {
// Merged format (.ctrltext.<col>): offset is the absolute byte position in the section.
if (offset >= ctrltext->get_size())
throw error(error::error_code::internal_error, "merged ctrltext offset out of range:"
+ std::to_string(offset) + "\n");
bd_data_ptr = reinterpret_cast<uint32_t*>(const_cast<char*>(ctrltext->get_data()) + offset);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use const_cast to remove const qualifier [cppcoreguidelines-pro-type-const-cast]

    bd_data_ptr = reinterpret_cast<uint32_t*>(const_cast<char*>(ctrltext->get_data()) + offset);
                                              ^

} else {
// Per-page format (.ctrltext.<col>.<page>): offset = T_N + D_bd.
// Adjust to index into the paired ctrldata section.
auto [col, page] = get_column_and_page(section_name);
auto id = get_grp_id_if_group_elf(section_name);
auto ctrldata = m_elfio.sections[get_ctrldata_section_name(col, page, id)];
if (!ctrldata)
throw error(error::error_code::internal_error, "ctrldata section for col:"
+ std::to_string(col) + " page:" + std::to_string(page) + " not found\n");
if (offset < ctrltext->get_size())
throw error(error::error_code::internal_error, "ctrldata size lesser than offset:"
+ std::to_string(offset) + "\n");
uint32_t data_offset = offset - static_cast<uint32_t>(ctrltext->get_size()) + elf_section_header_size;
if (data_offset > ctrldata->get_size())
throw error(error::error_code::internal_error, "ctrldata offset out of range:"
+ std::to_string(offset) + "\n");
bd_data_ptr = reinterpret_cast<uint32_t*>(const_cast<char*>(ctrldata->get_data()) + data_offset);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use const_cast to remove const qualifier [cppcoreguidelines-pro-type-const-cast]

    bd_data_ptr = reinterpret_cast<uint32_t*>(const_cast<char*>(ctrldata->get_data()) + data_offset);
                                              ^

}

// Write BD based on schema (AIE2PS vs AIE4)
switch(schema) {
case symbol::patch_schema::shim_dma_57:
write57(bd_data_ptr, bd_offset);
Expand Down
70 changes: 66 additions & 4 deletions src/cpp/analyzer/transform_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,31 @@ class transform_manager {
uint32_t size(const isa_op_disasm& op) const;

/**
* @brief Modify apply_offset_57 opcodes with XRT argument indices
* @brief Modify apply_offset_57 opcodes with XRT argument indices (legacy per-page format)
* @param text_section_data Pointer to text section data
* @param text_section_size Size of text section
* @param section_idx Section index in ELF
*/
void modify_apply_offset_57(char* text_section_data, size_t text_section_size, uint32_t section_idx);

/**
* @brief Modify apply_offset_57 opcodes for the merged single-section format.
*
* In the merged format a single .ctrltext.<col> section holds all pages
* concatenated, each occupying PAGE_SIZE bytes:
* [header 16B][text][data][padding to PAGE_SIZE]
*
* This function iterates over each page's text portion using cur_page_len
* from the page header and adjusts the table_ptr lookup by the page's base
* offset (page_index * PAGE_SIZE + 16) so that it matches the corrected
* r_offset stored in the ELF relocations.
Comment on lines +92 to +95
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new docstring for the merged format says the function “iterates over each page's text portion using cur_page_len from the page header”. In this codebase cur_page_len represents the total page length (header + text + data), so using it as a text boundary is misleading. Please update the comment to reflect the actual boundary detection used (or change the implementation to match the comment).

Suggested change
* This function iterates over each page's text portion using cur_page_len
* from the page header and adjusts the table_ptr lookup by the page's base
* offset (page_index * PAGE_SIZE + 16) so that it matches the corrected
* r_offset stored in the ELF relocations.
* This function walks each page in the merged section, interprets the page
* header (including cur_page_len, which describes the entire page payload),
* and adjusts the table_ptr lookup by the page's base offset
* (page_index * PAGE_SIZE + 16) so that it matches the r_offset values
* stored in the ELF relocations.

Copilot uses AI. Check for mistakes.
*
* @param section_data Pointer to the merged section data (writable)
* @param section_size Size of the merged section in bytes
* @param section_idx ELF section index used to build the lookup key
*/
void modify_apply_offset_57_merged(char* section_data, size_t section_size, uint32_t section_idx);

void process_sections();

/**
Expand All @@ -94,8 +112,9 @@ class transform_manager {

/**
* @brief Extract column and page from section name
* @param name Section name (e.g., ".ctrltext.0.1" or ".ctrltext.0.1.id")
* @return Pair of column and page indices
* @param name Section name (e.g., ".ctrltext.0.1", ".ctrltext.0.1.id",
* or merged ".ctrltext.0" which returns page=0)
* @return Pair of (column, page) indices
*/
std::pair<uint32_t, uint32_t> get_column_and_page(const std::string& name) const;

Expand Down Expand Up @@ -146,7 +165,7 @@ class transform_manager {
std::set<ELFIO::Elf_Half> get_filtered_section_indices(const std::string& kernel_instance_filter);

/**
* @brief Generate control text section name
* @brief Generate per-page control text section name
* @param col Column index
* @param page Page index
* @param id Group ID (empty for non-group ELF)
Expand All @@ -160,6 +179,20 @@ class transform_manager {
return ".ctrltext." + std::to_string(col) + "." + std::to_string(page) + "." + id;
}

/**
* @brief Generate merged (all-pages-in-one) control text section name
* @param col Column index
* @param id Group ID (empty for non-group ELF)
* @return Section name like ".ctrltext.col" or ".ctrltext.col.id"
*/
static std::string get_merged_ctrltext_section_name(uint32_t col, const std::string& id)
{
if (id.empty())
return ".ctrltext." + std::to_string(col);
else
return ".ctrltext." + std::to_string(col) + "." + id;
}

/**
* @brief Generate control data section name
* @param col Column index
Expand All @@ -175,6 +208,35 @@ class transform_manager {
return ".ctrldata." + std::to_string(col) + "." + std::to_string(page) + "." + id;
}

/**
* @brief Check if a section name is the merged (column-level) format
*
* Merged sections have the form ".ctrltext.<col>" — exactly two numeric
* tokens after splitting by '.'. Per-page sections have the form
* ".ctrltext.<col>.<page>" (three tokens) or ".ctrltext.<col>.<page>.<id>"
* (four tokens).
*
* @param name Section name to test
* @return true if the name is a merged ctrltext section
*/
static bool is_merged_section_name(const std::string& name)
{
if (name.size() < ctrltext_string_length ||
name.compare(0, ctrltext_string_length, ".ctrltext") != 0)
return false;
// Count dot-separated non-empty tokens
size_t token_count = 0;
size_t pos = 0;
while (pos < name.size()) {
size_t dot = name.find('.', pos + 1);
if (dot == std::string::npos) dot = name.size();
if (dot > pos + 1) ++token_count;
pos = dot;
}
// ".ctrltext.<col>" has exactly 2 tokens (ctrltext, col)
return token_count == 2;
}

/**
* @brief Check if section name is a control text section
* @param section_name Section name to check
Expand Down
6 changes: 3 additions & 3 deletions src/cpp/elf/aie_elf_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ constexpr unsigned char osabi_aie4z = 0x69; // 105 - AIE4Z
// ELF ABI Version values
// Encoding: upper nibble = major version, lower nibble = minor version
// ============================================================================
constexpr unsigned char elf_version_legacy = 0x02; // 0.2 - Non-config (all architectures)
constexpr unsigned char elf_version_legacy_config = 0x03; // 0.3 - Legacy config (aie2ps/aie4 without .target)
constexpr unsigned char elf_version_legacy = 0x03; // 0.3 - Non-config (all architectures)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the ELF has OS_ABI version as 0x46 and ABI version as 0x03, it matches both the categories: per page based full ELF and merged-page based non/legacy ELF. XRT/elf_loader will fail to identify the correct ELF. Please check

constexpr unsigned char elf_version_legacy_config = 0x04; // 0.4 - Legacy config (aie2ps/aie4 without .target)
constexpr unsigned char elf_version_aie2p_config = 0x10; // 1.0 - Legacy AIE2P config (read-only, no longer written)
constexpr unsigned char elf_version_config = 0x20; // 2.0 - Config with .target or aie2/aie2p config
constexpr unsigned char elf_version_config = 0x21; // 2.1 - Config with .target or aie2/aie2p config

}
#endif // AIEBU_ELF_AIE_ELF_CONSTANTS_H_
Loading
Loading