From d87b3215a7dcd5ff97c7da984283e5330ee6b4c7 Mon Sep 17 00:00:00 2001
From: Jason Hiser <jdhiser@gmail.com>
Date: Sat, 9 Feb 2019 16:35:20 -0500
Subject: [PATCH] fixed filesz setting in phdr

---
 include/elfwrite.h |   2 +
 src/elfwrite.cpp   | 101 ++++++++++++++++++++++++++++-----------------
 2 files changed, 66 insertions(+), 37 deletions(-)

diff --git a/include/elfwrite.h b/include/elfwrite.h
index 5fae1ad33..b3d176d89 100644
--- a/include/elfwrite.h
+++ b/include/elfwrite.h
@@ -173,6 +173,8 @@ class ElfWriterImpl : public ElfWriter
 		IRDB_SDK::DataScoop_t* find_scoop_by_name(const std::string& name, IRDB_SDK::FileIR_t* );
 		void AddSections(FILE* fout);
 		void update_phdr_for_scoop_sections(IRDB_SDK::FileIR_t* );
+		void trim_last_segment_filesz(IRDB_SDK::FileIR_t* firp);
+
 		void WriteElf(FILE* fout);
 	private:
 		unsigned int DetermineMaxPhdrSize();
diff --git a/src/elfwrite.cpp b/src/elfwrite.cpp
index da648b577..b870ebcbd 100644
--- a/src/elfwrite.cpp
+++ b/src/elfwrite.cpp
@@ -23,6 +23,10 @@ using namespace zipr;
 using namespace ELFIO;
 
 
+static inline uintptr_t page_round_down(uintptr_t x)
+{
+	return x & (~(PAGE_SIZE-1));
+}
 static inline uintptr_t page_round_up(uintptr_t x)
 {
         return  ( (((uintptr_t)(x)) + PAGE_SIZE-1)  & (~(PAGE_SIZE-1)) );
@@ -187,13 +191,6 @@ void ElfWriter::CreateSegmap(const ELFIO::elfio *elfiop, FileIR_t* firp, const s
 		// if we switch perms, or skip a page 
 		if( (perms.m_perms!=segperms.m_perms) || (segend!=pagestart))
 		{
-/*
-			LoadSegment_t *seg=new LoadSegment_t;
-			seg->memsz=segend-segstart;
-			seg->filesz=initend-segstart;
-			seg->start_page=segstart;
-			seg->m_perms=segperms.m_perms;
-*/
 			const auto seg=new LoadSegment_t(initend-segstart, segend-segstart, 0, segstart,segperms.m_perms);
 			segvec.push_back(seg);
 
@@ -204,32 +201,19 @@ void ElfWriter::CreateSegmap(const ELFIO::elfio *elfiop, FileIR_t* firp, const s
 			segend=segstart+PAGE_SIZE;
 
 			update_initend(perms);
-/*
-			if( should_bss_optimize(perms) ) // perms.is_zero_initialized() && m_bss_opts)
-				initend=segstart;
-			else
-				initend=segend;
-*/
 
 		}
 		else
 		{
 			// else, same permission and next page, extend segment. 
 			segend=pagestart+PAGE_SIZE;
-			if(! should_bss_optimize(perms) ) // !perms.is_zero_initialized() || ! m_bss_opts)
+			if(! should_bss_optimize(perms) ) 
 				initend=pagestart+PAGE_SIZE;
 		}
 		
 	}
 
 	// make sure we print the last one
-/*
-	LoadSegment_t *seg=new LoadSegment_t;
-	seg->memsz=segend-segstart;
-	seg->filesz=initend-segstart;
-	seg->start_page=segstart;
-	seg->m_perms=segperms.m_perms;
-*/
 	const auto seg=new LoadSegment_t(initend-segstart, segend-segstart, 0, segstart,segperms.m_perms);
 	segvec.push_back(seg);
 
@@ -553,6 +537,53 @@ void  ElfWriterImpl<T_Elf_Ehdr,T_Elf_Phdr,T_Elf_Addr,T_Elf_Shdr,T_Elf_Sym, T_Elf
 	}
 	return;
 }
+template <class T_Elf_Ehdr, class T_Elf_Phdr, class T_Elf_Addr, class T_Elf_Shdr, class T_Elf_Sym, class T_Elf_Rel, class T_Elf_Rela, class T_Elf_Dyn>
+void ElfWriterImpl<T_Elf_Ehdr,T_Elf_Phdr,T_Elf_Addr,T_Elf_Shdr,T_Elf_Sym, T_Elf_Rel, T_Elf_Rela, T_Elf_Dyn>::trim_last_segment_filesz(FileIR_t* firp)
+{
+	// skip trimming if we aren't doing bss optimization.
+	if(!m_bss_opts) return;
+
+
+	// find the last pt load segment header.
+	auto seg_to_trim=-1;
+	for(auto i=0u;i<new_phdrs.size(); i++)
+	{
+		if(new_phdrs[i].p_type==PT_LOAD)
+		{
+			seg_to_trim=i;
+		}
+		
+	}
+	assert(seg_to_trim!=-1);
+
+
+	
+
+	const auto seg_start_addr=new_phdrs[seg_to_trim].p_vaddr;
+	const auto seg_filesz=new_phdrs[seg_to_trim].p_filesz;
+	const auto seg_end_addr=seg_start_addr+seg_filesz-1;
+	const auto seg_end_page_start=page_round_down(seg_end_addr);
+	const auto &page=pagemap[seg_end_page_start];
+
+	// don't write 0's at end of last page 
+	auto k=PAGE_SIZE-1;
+	for (/* above */; k>=0; k--)
+	{
+		if(page.data[k]!=0)
+			break;
+	}
+	const auto last_nonzero_byte_in_seg = k;
+	const auto bytes_to_trim = (PAGE_SIZE - 1) - last_nonzero_byte_in_seg;	
+
+	// lastly, update the filesz so we don't need the reste of those bytes.
+	// memsz is allowed to be bigger than filesz.
+	new_phdrs[seg_to_trim].p_filesz -= bytes_to_trim;
+
+	return;
+
+}
+
+
 
 
 template <class T_Elf_Ehdr, class T_Elf_Phdr, class T_Elf_Addr, class T_Elf_Shdr, class T_Elf_Sym, class T_Elf_Rel, class T_Elf_Rela, class T_Elf_Dyn>
@@ -693,30 +724,16 @@ bool ElfWriterImpl<T_Elf_Ehdr,T_Elf_Phdr,T_Elf_Addr,T_Elf_Shdr,T_Elf_Sym, T_Elf_
 	std::vector<T_Elf_Phdr> relro_phdrs;
 	new_phdrs.insert(new_phdrs.end(), relro_phdrs.begin(), relro_phdrs.end());
 
-#ifdef CGC
-// 
-// Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
-// LOAD           0x000f20 0x00000000 0x00000000 0x00000 0x00000       0x1000 (edited)
-	// create 0-size headre
-	std::cout<<"New phdrs at: "<<std::hex<<new_phdr_addr<<std::endl;
-	T_Elf_Phdr aqphdr;
-	memset(&aqphdr,0,sizeof(aqphdr));
-	aqphdr.p_type = PT_LOAD;
-	aqphdr.p_offset =phdr_map_offset; 
-	aqphdr.p_align =0x1000;
-	new_phdrs.insert(new_phdrs.begin(),aqphdr);
-#endif
-
 	// record the new ehdr.
 	new_ehdr=ehdr;
 	new_ehdr.e_phoff=phdr_map_offset;
 	new_ehdr.e_shoff=0;
 	new_ehdr.e_shnum=0;
 	new_ehdr.e_phnum=new_phdrs.size();
-	// new_ehdr.e_phoff=sizeof(new_ehdr);
 	new_ehdr.e_shstrndx=0;
 
 	update_phdr_for_scoop_sections(m_firp);
+	trim_last_segment_filesz(m_firp);
 
 
 	return true;
@@ -751,6 +768,11 @@ void ElfWriterImpl<T_Elf_Ehdr,T_Elf_Phdr,T_Elf_Addr,T_Elf_Shdr,T_Elf_Sym, T_Elf_
 				}
 				else
 				{
+#if 0
+note:  this does not work on centos as it leaves  the segments
+start address + filesize to be a number greater than the entire files size.
+This causes the loader to complain.  The "right" way to do this is to update the
+filesz before we start writing out the elf.  See "trim_last_seg_filesz"
 					// don't write 0's at end of last page 
 					int k=0;
 					for (k=PAGE_SIZE-1;k>=0;k--)
@@ -759,7 +781,12 @@ void ElfWriterImpl<T_Elf_Ehdr,T_Elf_Phdr,T_Elf_Addr,T_Elf_Shdr,T_Elf_Sym, T_Elf_
 							break;
 					}
 					std::cout<<"phdr["<<std::dec<<loadcnt<<"] optimizing last page write to size k="<<std::hex<<k<<std::endl;
-					fwrite(page.data.data(), k+1, 1, fout);
+#endif
+					const auto end_offset=new_phdrs[i].p_filesz;
+					const auto current_offset = j;
+					const auto bytes_to_write = end_offset - current_offset;
+					assert(bytes_to_write <= PAGE_SIZE);
+					fwrite(page.data.data(), bytes_to_write, 1, fout);
 				}
 		
 			}
-- 
GitLab