Skip to content

Commit 5d6d887

Browse files
committed
abnativeelf: use elf_begin without memory mapping on 32-bit targets
32-bit targets have less memory space to map large binary files concurrently. Use elf_begin() to let libelf to open and read the ELF file itself instead of memory mapping them. Observed when compiling LLVM on i486, which has 3GiB of user memory space.
1 parent e02a57c commit 5d6d887

File tree

1 file changed

+47
-32
lines changed

1 file changed

+47
-32
lines changed

native/abnativeelf.cpp

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ constexpr uint32_t elf_flags_mips64r6el = EF_MIPS_ARCH_64R6 | EF_MIPS_NAN2008;
4949

5050
constexpr uint32_t elf_min_size = sizeof(Elf32_Ehdr);
5151

52+
// 4KiB.
53+
constexpr size_t min_map_size = 4 * (1 << 20);
54+
5255
enum class Endianness : bool {
5356
Little = true,
5457
Big = false,
@@ -394,9 +397,36 @@ const AOSCArch detect_architecture(Elf *elf_file, GElf_Ehdr &elf_ehdr,
394397
}
395398
}
396399

397-
static ELFParseResult identify_binary_data(const char *data,
398-
const size_t size) {
400+
class MappedFile {
401+
public:
402+
MappedFile(int fd, size_t size) : m_fd{fd}, m_size{size} {
403+
if (m_fd == -1) {
404+
m_addr = MAP_FAILED;
405+
return;
406+
}
407+
m_addr = mmap(nullptr, m_size, PROT_READ, MAP_PRIVATE, m_fd, 0);
408+
}
409+
~MappedFile() {
410+
if (m_addr != MAP_FAILED)
411+
munmap(m_addr, m_size);
412+
if (m_fd >= 0)
413+
close(m_fd);
414+
}
415+
inline void *addr() const { return m_addr; }
416+
inline size_t size() const { return m_size; }
417+
418+
private:
419+
int m_fd;
420+
void *m_addr;
421+
size_t m_size;
422+
};
423+
424+
static ELFParseResult identify_binary_data(const char *path, int fd,
425+
const struct stat *st) {
399426
ELFParseResult result{};
427+
size_t size = st->st_size > min_map_size ? min_map_size : st->st_size;
428+
const MappedFile file{fd, size};
429+
const char *data = static_cast<const char *>(file.addr());
400430
const bool is_static_library =
401431
(size >= 8 && memcmp(data, ar_magic.data(), ar_magic.size()) == 0) ||
402432
(size >= 8 &&
@@ -422,8 +452,19 @@ static ELFParseResult identify_binary_data(const char *data,
422452
result.bin_type = BinaryType::Invalid;
423453
return result;
424454
}
425-
426-
Elf *elf_file = elf_memory(const_cast<char *>(data), size);
455+
/*
456+
* NOTE: Do not mmap entire files in parallel on 32-bit targets, since
457+
* they have much less address space to work with.
458+
*/
459+
#ifdef __LP64__
460+
size_t full_size = st->st_size;
461+
const MappedFile full_file = {fd, full_size};
462+
const char *full_data = static_cast<const char *>(full_file.addr());
463+
Elf *elf_file = elf_memory(const_cast<char *>(full_data), full_size);
464+
#else
465+
elf_version(EV_CURRENT);
466+
Elf *elf_file = elf_begin(fd, ELF_C_READ, nullptr);
467+
#endif
427468
GElf_Ehdr elf_ehdr{};
428469
gelf_getehdr(elf_file, &elf_ehdr);
429470
const char *shstr_start = nullptr;
@@ -504,30 +545,6 @@ inline static fs::path get_filename_from_build_id(const std::string &build_id,
504545
return final_path;
505546
}
506547

507-
class MappedFile {
508-
public:
509-
MappedFile(int fd, size_t size) : m_fd{fd}, m_size{size} {
510-
if (m_fd == -1) {
511-
m_addr = MAP_FAILED;
512-
return;
513-
}
514-
m_addr = mmap(nullptr, m_size, PROT_READ, MAP_PRIVATE, m_fd, 0);
515-
}
516-
~MappedFile() {
517-
if (m_addr != MAP_FAILED)
518-
munmap(m_addr, m_size);
519-
if (m_fd >= 0)
520-
close(m_fd);
521-
}
522-
inline void *addr() const { return m_addr; }
523-
inline size_t size() const { return m_size; }
524-
525-
private:
526-
int m_fd;
527-
void *m_addr;
528-
size_t m_size;
529-
};
530-
531548
static inline int forked_execvp(const char *path, char *const argv[]) {
532549
const pid_t pid = fork();
533550
if (pid == 0) {
@@ -646,15 +663,13 @@ int elf_copy_debug_symbols(const char *src_path, const char *dst_path,
646663
perror("fstat");
647664
return -1;
648665
}
649-
const size_t size = st.st_size;
650-
const MappedFile file{fd, size};
666+
651667
std::vector<const char *> args{"", "--remove-section=.comment",
652668
"--remove-section=.note"};
653669
std::vector<const char *> extra_args{}; // for binutils
654670
args.reserve(8);
655671
extra_args.reserve(1);
656-
const char *data = static_cast<const char *>(file.addr());
657-
const ELFParseResult result = identify_binary_data(data, size);
672+
const ELFParseResult result = identify_binary_data(src_path, fd, &st);
658673

659674
constexpr const char *base_path = "/usr/lib/";
660675
constexpr const size_t base_len = sizeof(base_path);

0 commit comments

Comments
 (0)