-
Notifications
You must be signed in to change notification settings - Fork 0
Adjust symtab section header #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d823f1c
a145bf1
9c7236d
f1fd105
3a54b40
c2de6af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| require "set" | ||
| require "caotral/binary/elf" | ||
|
|
||
| module Caotral | ||
| class Linker | ||
| class Builder | ||
| SYMTAB_BIND = { locals: 0, globals: 1, weaks: 2, }.freeze | ||
| BIND_BY_VALUE = SYMTAB_BIND.invert.freeze | ||
| attr_reader :symbols | ||
|
|
||
| def initialize(elf_obj:) | ||
| @elf_obj = elf_obj | ||
| @symbols = { locals: Set.new, globals: Set.new, weaks: Set.new } | ||
| end | ||
| def resolve_symbols | ||
| @elf_obj.find_by_name(".symtab").body.each do |symtab| | ||
| name = symtab.name_string | ||
| next if name.empty? | ||
| info = symtab.info | ||
| bind = BIND_BY_VALUE.fetch(info >> 4) | ||
| if bind == :globals && @symbols[bind].include?(name) | ||
| raise Caotral::Binary::ELF::Error,"cannot add into globals: #{name}" | ||
| end | ||
| @symbols[bind] << name | ||
| end | ||
| @symbols | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,6 @@ module Caotral | |
| class Linker | ||
| class Writer | ||
| include Caotral::Binary::ELF::Utils | ||
| ALLOW_SECTIONS = %w(.text .strtab .shstrtab).freeze | ||
| R_X86_64_PC32 = 2 | ||
| R_X86_64_PLT32 = 4 | ||
| ALLOW_RELOCATION_TYPES = [R_X86_64_PC32, R_X86_64_PLT32].freeze | ||
|
|
@@ -15,6 +14,7 @@ def self.write!(elf_obj:, output:, entry: nil, debug: false) | |
| end | ||
| def initialize(elf_obj:, output:, entry: nil, debug: false) | ||
| @elf_obj, @output, @entry, @debug = elf_obj, output, entry, debug | ||
| @write_sections = write_order_sections | ||
| end | ||
| def write | ||
| f = File.open(@output, "wb") | ||
|
|
@@ -58,6 +58,7 @@ def write | |
| end | ||
| target.body = bytes | ||
| end | ||
|
|
||
| header.set!(entry: @entry || base_addr + text_offset) | ||
| ph.set!(type:, offset: text_offset, vaddr:, paddr:, filesz:, memsz:, flags:, align:) | ||
| text_section.header.set!(size: text_section.body.bytesize, addr: vaddr, offset: text_offset) | ||
|
|
@@ -70,17 +71,28 @@ def write | |
| shstrtab_offset = f.pos | ||
| f.write(shstrtab.body.names) | ||
| shstrtab.header.set!(offset: shstrtab_offset, size: shstrtab.body.names.bytesize) | ||
| write_sections = @elf_obj.sections.select { ALLOW_SECTIONS.include?(it.section_name) || it.section_name.nil? } | ||
| shoffset = f.pos | ||
| shstrndx = write_sections.index { it.section_name == ".shstrtab" } | ||
| shnum = write_sections.size | ||
| shstrndx = write_section_index(".shstrtab") | ||
| strtabndx = write_section_index(".strtab") | ||
| symtabndx = write_section_index(".symtab") | ||
| shnum = @write_sections.size | ||
| @elf_obj.header.set!(shoffset:, shnum:, shstrndx:) | ||
| names = @elf_obj.find_by_name(".shstrtab").body | ||
|
|
||
| write_sections.each do |section| | ||
| @write_sections.each do |section| | ||
| header = section.header | ||
| lookup_name = section.section_name | ||
| name_offset = names.offset_of(lookup_name) | ||
| section.header.set!(name: name_offset) if name_offset | ||
| name, info, link, entsize = (name_offset.nil? ? 0 : name_offset), header.info, header.link, 0 | ||
| if header.type == :symtab | ||
| info = section.body.size | ||
| link = strtabndx | ||
| entsize = header.entsize.nonzero? || 24 | ||
| elsif [:rel, :rela].include?(header.type) | ||
| link = symtabndx | ||
| info = ref_index(section) | ||
| end | ||
| header.set!(name:, info:, link:, entsize:) | ||
| f.write(section.header.build) | ||
| end | ||
|
|
||
|
|
@@ -90,6 +102,24 @@ def write | |
| ensure | ||
| f.close if f | ||
| end | ||
|
|
||
| private | ||
| def write_order_sections | ||
| write_order = [] | ||
| write_order << @elf_obj.sections.find { |s| s.section_name.nil? } | ||
| write_order << @elf_obj.find_by_name(".text") | ||
| write_order << @elf_obj.find_by_name(".symtab") | ||
| write_order << @elf_obj.find_by_name(".strtab") | ||
| write_order.concat(@elf_obj.select_by_names([/\.rel\./, /\.rela\./])) | ||
| write_order << @elf_obj.find_by_name(".shstrtab") | ||
|
Comment on lines
+110
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The write order now includes every Useful? React with 👍 / 👎. |
||
| write_order.compact | ||
| end | ||
| def write_section_index(section_name) = @write_sections.index { it.section_name == section_name } | ||
| def ref_index(section) | ||
| section_name = section.section_name | ||
| ref = @elf_obj.select_by_names(section_name.split(".").filter { |sn| !sn.empty? && sn != "rel" && sn != "rela" }.map { "." + it }).first | ||
| write_section_index(ref.section_name) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| class Caotral::Linker::Builder | ||
| @elf_obj: Caotral::Binary::ELF | ||
| @symbols: Hash[Symbol, Set[String]] | ||
|
|
||
| attr_reader symbols: Hash[Symbol, Set[String]] | ||
|
|
||
| def initialize: (elf_obj: Caotral::Binary::ELF) -> void | ||
| def resolve_symbols: () -> Hash[Symbol, Set[String]] | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In ELF, a symtab section’s
sh_infomust be the index of the first non-local symbol (i.e., the count of local symbols). Hereinfo = section.body.sizesets it to the total symbol count, so any global symbols are effectively marked as local to consumers that rely onsh_info. This shows up whenever the input has globals (e.g., themainsymbol from the assembler or GCC-produced objects), and it can cause tools/linkers to misclassify or ignore globals.Useful? React with 👍 / 👎.