This patch teaches libiberty to output X86-64 Relocations. From d3b2d168369e76a6fac2b3b3cbd591ccf22ea8ea Mon Sep 17 00:00:00 2001 From: Rishi Raj Date: Mon, 23 Oct 2023 06:22:44 +0530 Subject: [PATCH 1/3] Extended libiberty to output X86_64 relocations Signed-off-by: Rishi Raj --- include/simple-object.h | 11 +- libiberty/simple-object-common.h | 28 ++- libiberty/simple-object-elf.c | 317 ++++++++++++++++++++++++++----- libiberty/simple-object.c | 95 +++++++-- 4 files changed, 387 insertions(+), 64 deletions(-) diff --git a/include/simple-object.h b/include/simple-object.h index 3a14184b12c..17ecd856636 100644 --- a/include/simple-object.h +++ b/include/simple-object.h @@ -186,6 +186,14 @@ simple_object_write_add_data (simple_object_write *simple_object, simple_object_write_section *section, const void *buffer, size_t size, int copy, int *err); +/* Add relocation to SECTION in SIMPLE_OBJECT */ +void +simple_object_write_add_relocation (simple_object_write_section *section, + unsigned long offset, long addend, const char *name, unsigned long rel_sec_idx); + +/* Modifies simple object section buffer at offset. */ +void simple_object_modify_buffer (simple_object_write_section *section, + unsigned long offset, unsigned char *buffer, int copy); /* Write the complete object file to DESCRIPTOR, an open file descriptor. This returns NULL on success. On error this returns @@ -199,7 +207,8 @@ simple_object_write_to_file (simple_object_write *simple_object, object_write_to_file function*/ extern void simple_object_write_add_symbol(simple_object_write *sobj, const char *name, -size_t size, unsigned int align); + unsigned int value, size_t size, unsigned char bind, + unsigned char type, unsigned short int shndx, unsigned char st_other); /* Release all resources associated with SIMPLE_OBJECT, including any simple_object_write_section's that may have been created. */ diff --git a/libiberty/simple-object-common.h b/libiberty/simple-object-common.h index df99c9d85ac..1dc06908eec 100644 --- a/libiberty/simple-object-common.h +++ b/libiberty/simple-object-common.h @@ -73,9 +73,17 @@ struct simple_object_symbol_struct /*The name of this symbol. */ char *name; /* Symbol value */ - unsigned int align; + unsigned int value; /* Symbol size */ size_t size; + /*Symbol binding*/ + unsigned char bind; + /*Symbol info*/ + unsigned char type; + /*Symbol section index*/ + unsigned short int shndx; + /* Symbol visibility */ + unsigned char st_other; }; /* A section in an object file being created. */ @@ -93,6 +101,11 @@ struct simple_object_write_section_struct struct simple_object_write_section_buffer *buffers; /* The last data attached to this section. */ struct simple_object_write_section_buffer *last_buffer; + /*The first relocation attached to this section. */ + struct simple_object_write_section_relocation *relocations; + /* The last relocation attache to this section. */ + struct simple_object_write_section_relocation *last_relocation; + }; /* Data attached to a section. */ @@ -108,6 +121,19 @@ struct simple_object_write_section_buffer /* A buffer to free, or NULL. */ void *free_buffer; }; +struct simple_object_write_section_relocation +{ + /* The next relocation for this section. */ + struct simple_object_write_section_relocation *next; + /* The offset. */ + unsigned long offset; + /* Addend */ + long addend; + /* Relocation symbol */ + const char *name; + /* Relocation symbol st_shndx wrt .debug_info index */ + unsigned long rel_sec_idx; +}; /* The number of bytes we read from the start of the file to pass to the match function. */ diff --git a/libiberty/simple-object-elf.c b/libiberty/simple-object-elf.c index 86b7a27dc74..0bbaf4b489f 100644 --- a/libiberty/simple-object-elf.c +++ b/libiberty/simple-object-elf.c @@ -238,6 +238,7 @@ typedef struct #define STT_NOTYPE 0 /* Symbol type is unspecified */ #define STT_OBJECT 1 /* Symbol is a data object */ #define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol is associate with a section */ #define STT_TLS 6 /* Thread local data object */ #define STT_GNU_IFUNC 10 /* Symbol is an indirect code object */ @@ -248,6 +249,63 @@ typedef struct #define STV_DEFAULT 0 /* Visibility is specified by binding type */ #define STV_HIDDEN 2 /* Can only be seen inside currect component */ +typedef struct +{ + unsigned char r_offset[4]; /* Address */ + unsigned char r_info[4]; /* relocation type and symbol index */ +} Elf32_External_Rel; + +typedef struct +{ + unsigned char r_offset[8]; /* Address */ + unsigned char r_info[8]; /* Relocation type and symbol index */ +} Elf64_External_Rel; +typedef struct +{ + unsigned char r_offset[4]; /* Address */ + unsigned char r_info[4]; /* Relocation type and symbol index */ + char r_addend[4]; /* Addend */ +} Elf32_External_Rela; +typedef struct +{ + unsigned char r_offset[8]; /* Address */ + unsigned char r_info[8]; /* Relocation type and symbol index */ + unsigned char r_addend[8]; /* Addend */ +} Elf64_External_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type) ((((unsigned long) (sym)) << 32) + (type)) + +/* AMD x86-64 relocations. */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ + +/* Index into relocation symbol array */ +#define DEBUG_INFO_IDX 0 +#define DEBUG_ABBREV_IDX 1 +#define DEBUG_STR_IDX 2 +#define DEBUG_LINE_IDX 3 +#define DEBUG_LINE_STR_IDX 4 + /* Functions to fetch and store different ELF types, depending on the endianness and size. */ @@ -784,7 +842,11 @@ simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor, shnum = 0; for (section = sobj->sections; section != NULL; section = section->next) + { ++shnum; + if(section->relocations) + ++shnum; + } if (shnum > 0) { /* Add a section header for the dummy section, @@ -891,7 +953,7 @@ simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor, static int simple_object_elf_write_symbol(simple_object_write *sobj, int descriptor, - off_t offset, unsigned int st_name, unsigned int st_value, size_t st_size, + off_t offset, unsigned int st_name, unsigned long int st_value, size_t st_size, unsigned char st_info, unsigned char st_other, unsigned int st_shndx, const char **errmsg, int *err) { @@ -900,38 +962,57 @@ simple_object_elf_write_symbol(simple_object_write *sobj, int descriptor, const struct elf_type_functions* fns; unsigned char cl; size_t sym_size; - unsigned char buf[sizeof (Elf64_External_Shdr)]; + unsigned char buf[sizeof (Elf64_External_Sym)]; fns = attrs->type_functions; cl = attrs->ei_class; sym_size = (cl == ELFCLASS32 - ? sizeof (Elf32_External_Shdr) - : sizeof (Elf64_External_Shdr)); - memset (buf, 0, sizeof (Elf64_External_Shdr)); + ? sizeof (Elf32_External_Sym) + : sizeof (Elf64_External_Sym)); + memset (buf, 0, sizeof (Elf64_External_Sym)); + + ELF_SET_FIELD(fns, cl, Sym, buf, st_name, Elf_Word, st_name); + ELF_SET_FIELD(fns, cl, Sym, buf, st_value, Elf_Addr, st_value); + ELF_SET_FIELD(fns, cl, Sym, buf, st_size, Elf_Addr, st_size); + buf[4]=st_info; + buf[5]=st_other; + ELF_SET_FIELD(fns, cl, Sym, buf, st_shndx, Elf_Half, st_shndx); - if(cl==ELFCLASS32) - { - ELF_SET_FIELD(fns, cl, Sym, buf, st_name, Elf_Word, st_name); - ELF_SET_FIELD(fns, cl, Sym, buf, st_value, Elf_Addr, st_value); - ELF_SET_FIELD(fns, cl, Sym, buf, st_size, Elf_Addr, st_size); - buf[4]=st_info; - buf[5]=st_other; - ELF_SET_FIELD(fns, cl, Sym, buf, st_shndx, Elf_Half, st_shndx); - } - else - { - ELF_SET_FIELD(fns, cl, Sym, buf, st_name, Elf_Word, st_name); - buf[4]=st_info; - buf[5]=st_other; - ELF_SET_FIELD(fns, cl, Sym, buf, st_shndx, Elf_Half, st_shndx); - ELF_SET_FIELD(fns, cl, Sym, buf, st_value, Elf_Addr, st_value); - ELF_SET_FIELD(fns, cl, Sym, buf, st_size, Elf_Addr, st_size); - } return simple_object_internal_write(descriptor, offset,buf,sym_size, errmsg,err); } +/* Write out an ELF R_X86_64_32 relocation entry */ + +static int +simple_object_elf_write_relocation(simple_object_write *sobj, int descriptor, + off_t offset, unsigned long r_offset, unsigned long r_info, + long r_addend, const char **errmsg, int *err) +{ + struct simple_object_elf_attributes *attrs = + (struct simple_object_elf_attributes *) sobj->data; + const struct elf_type_functions* fns; + unsigned char cl; + size_t rel_size; + unsigned char buf[sizeof (Elf64_External_Rela)]; + + fns = attrs->type_functions; + cl = attrs->ei_class; + + rel_size = cl == ELFCLASS32? sizeof(Elf32_External_Rela): + sizeof(Elf64_External_Rela); + + memset (buf, 0, sizeof (Elf64_External_Rela)); + ELF_SET_FIELD(fns, cl, Rela, buf, r_offset, Elf_Addr, r_offset); + ELF_SET_FIELD(fns, cl, Rela, buf, r_info, Elf_Addr, r_info); + ELF_SET_FIELD(fns, cl, Rela, buf, r_addend, Elf_Addr, r_addend); + + return simple_object_internal_write(descriptor, offset, buf, rel_size, + errmsg,err); +} + + /* Write out a complete ELF file. Ehdr initial dummy Shdr @@ -978,15 +1059,19 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, shnum = 0; for (section = sobj->sections; section != NULL; section = section->next) + { ++shnum; + /* count the relocation section too if there exist any relocations */ + if(section->relocations) ++shnum; + } if (shnum == 0) return NULL; /* Add initial dummy Shdr and .shstrtab */ shnum += 2; /*add initial .symtab and .strtab if symbol exists */ - if(sobj->symbols) - shnum += 2; + if(sobj->symbols) + shnum += 2; shdr_offset = ehdr_size; sh_offset = shdr_offset + shnum * shdr_size; @@ -1008,6 +1093,15 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, sh_name = 1; secnum = 0; + unsigned int section_idx = 1; + unsigned int debug_info_idx=1; + /* Relocation symbol index will start from 1, 0 being dummy symbol */ + unsigned long sym_idx = 1; + /* An array to store the .symtab index of relocation symbol */ + unsigned long rel_symtab_idx[5]; + for(int i=0; i<5; i++) + rel_symtab_idx[i] = -1; + for (section = sobj->sections; section != NULL; section = section->next) { size_t mask; @@ -1087,7 +1181,69 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, shdr_offset += shdr_size; sh_name += strlen (section->name) + 1; sh_offset += sh_size; + if(!strcmp(section->name,".gnu.debuglto_.debug_info")) + debug_info_idx=section_idx; + ++section_idx; + /* If the section has relocation, write out the relocation section */ + if( section->relocations) + { + sh_size=0; + struct simple_object_write_section_relocation *relocation; + sh_entsize = cl == ELFCLASS32 ? sizeof(Elf32_External_Rela) : sizeof(Elf64_External_Rela); + + for(relocation = section->relocations; relocation != NULL; relocation = relocation->next) + { + + int idx=-1; + if(!strcmp(relocation->name,".gnu.debuglto_.debug_info")) + idx=DEBUG_INFO_IDX; + else if(!strcmp(relocation->name,".gnu.debuglto_.debug_abbrev")) + idx=DEBUG_ABBREV_IDX; + else if(!strcmp(relocation->name,".gnu.debuglto_.debug_str")) + idx=DEBUG_STR_IDX; + else if(!strcmp(relocation->name,".gnu.debuglto_.debug_line")) + idx=DEBUG_LINE_IDX; + else if(!strcmp(relocation->name,".gnu.debuglto_.debug_line_str")) + idx=DEBUG_LINE_STR_IDX; + if(idx < 0) + continue; + /* Add the relocation symbol to .symtab if it hasn't been already added */ + if(rel_symtab_idx[idx]==(unsigned long)-1) + { + simple_object_write_add_symbol(sobj,relocation->name, 0, 0, + STB_LOCAL, STT_SECTION, relocation->rel_sec_idx+debug_info_idx,0); + rel_symtab_idx[idx]=sym_idx; + sym_idx++; + } + /* write the relocation entry */ + unsigned long r_info = cl==ELFCLASS32 ? ELF32_R_INFO(rel_symtab_idx[idx], R_X86_64_32): + ELF64_R_INFO(rel_symtab_idx[idx], R_X86_64_32); + if(!simple_object_elf_write_relocation(sobj, descriptor, sh_offset+sh_size, + relocation->offset, r_info, relocation->addend, &errmsg, err)) + return errmsg; + sh_size+=sh_entsize; + + } + + sh_addralign = cl==ELFCLASS32 ? 0x04 : 0x08; + + if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, + sh_name, SHT_RELA, SHF_INFO_LINK, + 0, sh_offset, + sh_size, shnum-3, section_idx-1, + sh_addralign, sh_entsize, + &errmsg, err)) + return errmsg; + + + shdr_offset += shdr_size; + sh_name += (strlen(".rela")+strlen(section->name) + 1); + sh_offset += sh_size; + ++section_idx; + } + } + /*Write out the whole .symtab and .strtab*/ if(sobj->symbols) { @@ -1097,43 +1253,73 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, for(symbol=sobj->symbols; symbol!=NULL; symbol=symbol->next) { ++num_sym; - } + } - size_t sym_size = cl==ELFCLASS32?sizeof(Elf32_External_Sym):sizeof(Elf64_External_Sym); - size_t sh_addralign = cl==ELFCLASS32?0x04:0x08; - size_t sh_entsize = sym_size; - size_t sh_size = num_sym*sym_size; - unsigned int sh_info = 2; - if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, - sh_name, SHT_SYMTAB, 0, 0, sh_offset, - sh_size, shnum-2, sh_info, - sh_addralign,sh_entsize, &errmsg, err)) - return errmsg; - shdr_offset += shdr_size; - sh_name += strlen(".symtab")+1; - /*Writes out the dummy symbol */ + unsigned int st_name_size = 1; + unsigned int num_local_sym = 0; + size_t sh_entsize= cl==ELFCLASS32 ? sizeof(Elf32_External_Sym) : sizeof(Elf64_External_Sym); + size_t sh_addralign = cl==ELFCLASS32 ? 0x04 : 0x08; + size_t sh_size = 0; + /*Writes out the dummy symbol */ if(!simple_object_elf_write_symbol(sobj, descriptor, sh_offset, 0,0,0,0,0,SHN_UNDEF,&errmsg,err)) return errmsg; - sh_offset += sym_size; - unsigned int st_name=1; + sh_size += sh_entsize; + + /* First write all local symbols */ + for(symbol=sobj->symbols; symbol!=NULL; symbol=symbol->next) + { + if(symbol->bind!=STB_LOCAL) + continue; + ++num_local_sym; + unsigned int st_value = symbol->value; + unsigned int st_size = symbol->size; + unsigned short int st_shndx = symbol->shndx==(unsigned short int)-1 ? SHN_COMMON : symbol->shndx; + unsigned char st_info = ELF_ST_INFO(symbol->bind,symbol->type); + unsigned char st_other = symbol->st_other; + + if(!simple_object_elf_write_symbol(sobj, descriptor, sh_offset+sh_size, + st_name_size,st_value,st_size,st_info,st_other,st_shndx,&errmsg,err)) + return errmsg; + + sh_size += sh_entsize; + st_name_size += strlen(symbol->name)+1; + + } + /* Write out the global and other symbols */ for(symbol=sobj->symbols; symbol!=NULL; symbol=symbol->next) { - unsigned int st_value = 1; - unsigned int st_size = 1; - unsigned char st_info = 17; - if(!simple_object_elf_write_symbol(sobj, descriptor, sh_offset, - st_name,st_value,st_size,st_info,0,SHN_COMMON,&errmsg,err)) + if(symbol->bind==STB_LOCAL) + continue; + unsigned int st_value = symbol->value; + unsigned int st_size = symbol->size; + unsigned short int st_shndx = symbol->shndx==(unsigned short int)-1 ? SHN_COMMON : symbol->shndx; + unsigned char st_info = ELF_ST_INFO(symbol->bind,symbol->type); + unsigned char st_other = symbol->st_other; + + if(!simple_object_elf_write_symbol(sobj, descriptor, sh_offset+sh_size, + st_name_size,st_value,st_size,st_info,st_other,st_shndx,&errmsg,err)) return errmsg; - sh_offset += sym_size; - st_name += strlen(symbol->name)+1; + + sh_size += sh_entsize; + st_name_size += strlen(symbol->name)+1; } + unsigned int sh_info = num_local_sym+1; + if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, + sh_name, SHT_SYMTAB, 0, 0, sh_offset, + sh_size, shnum-2, sh_info, + sh_addralign,sh_entsize, &errmsg, err)) + return errmsg; + shdr_offset += shdr_size; + sh_offset+=sh_size; + sh_name += strlen(".symtab")+1; + if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, sh_name, SHT_STRTAB, 0, 0, sh_offset, - st_name, 0, 0, + st_name_size, 0, 0, 1, 0, &errmsg, err)) return errmsg; shdr_offset += shdr_size; @@ -1144,10 +1330,25 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, &errmsg, err)) return errmsg; ++sh_offset; + /* write out the local symbols name */ + for(symbol = sobj->symbols; symbol!=NULL; symbol = symbol->next) + { + if(symbol->bind != STB_LOCAL) + continue; + size_t len = strlen(symbol->name)+1; + if (!simple_object_internal_write (descriptor, sh_offset, + (const unsigned char *) symbol->name, + len, &errmsg, err)) + return errmsg; + sh_offset += len; + } + /* write out the global and other symbols name */ for(symbol=sobj->symbols;symbol!=NULL;symbol=symbol->next) { - size_t len=strlen(symbol->name)+1; + if(symbol->bind == STB_LOCAL) + continue; + size_t len = strlen(symbol->name)+1; if (!simple_object_internal_write (descriptor, sh_offset, (const unsigned char *) symbol->name, len, &errmsg, err)) @@ -1179,6 +1380,22 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, len, &errmsg, err)) return errmsg; sh_offset += len; + + if(section->relocations) + { + /* Adds the .rela prefix and write it to .shstrtab */ + if (!simple_object_internal_write (descriptor, sh_offset, + (const unsigned char *) ".rela",strlen(".rela"), &errmsg, err)) + return errmsg; + + sh_offset += strlen(".rela"); + len = strlen (section->name) + 1; + if (!simple_object_internal_write (descriptor, sh_offset, + (const unsigned char *) section->name, + len, &errmsg, err)) + return errmsg; + sh_offset += len; + } } /*Adds the name .symtab and .strtab*/ if(sobj->symbols) diff --git a/libiberty/simple-object.c b/libiberty/simple-object.c index 1f9141aedb4..dcdd129a869 100644 --- a/libiberty/simple-object.c +++ b/libiberty/simple-object.c @@ -476,6 +476,8 @@ simple_object_write_create_section (simple_object_write *sobj, const char *name, ret->align = align; ret->buffers = NULL; ret->last_buffer = NULL; + ret->relocations = NULL; + ret->last_relocation = NULL; if (sobj->last_section == NULL) { @@ -532,6 +534,60 @@ simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED, return NULL; } +/* Add relocation to a section. */ + +void +simple_object_write_add_relocation (simple_object_write_section *section, + unsigned long offset, long addend, const char *name, unsigned long rel_sec_idx) +{ + struct simple_object_write_section_relocation *wsr; + + wsr = XNEW (struct simple_object_write_section_relocation); + wsr->next = NULL; + wsr->offset = offset; + wsr->addend = addend; + wsr->name = name; + wsr->rel_sec_idx = rel_sec_idx; + + if (section->last_relocation == NULL) + { + section->relocations = wsr; + section->last_relocation = wsr; + } + else + { + section->last_relocation->next = wsr; + section->last_relocation = wsr; + } + +} + +void simple_object_modify_buffer (simple_object_write_section *section, + unsigned long offset, unsigned char *buffer, int copy) +{ + struct simple_object_write_section_buffer *wsb; + unsigned long curr_offset = 0; + for(wsb = section->buffers; wsb != NULL; wsb=wsb->next) + { + if(offset == curr_offset) + { + if (!copy) + { + wsb->buffer = buffer; + wsb->free_buffer = NULL; + } + else + { + wsb->free_buffer = (void *) XNEWVEC (char, wsb->size); + memcpy (wsb->free_buffer, buffer, wsb->size); + wsb->buffer = wsb->free_buffer; + } + } + curr_offset+=wsb->size; + } + +} + /* Write the complete object file. */ const char * @@ -540,26 +596,32 @@ simple_object_write_to_file (simple_object_write *sobj, int descriptor, { return sobj->functions->write_to_file (sobj, descriptor, err); } -/*Adds a symbol in to common*/ +/* Adds a symbol to .symtab. If shndx is -1 add it to COMMON */ void -simple_object_write_add_symbol(simple_object_write *sobj, const char *name, -size_t size, unsigned int align) +simple_object_write_add_symbol(simple_object_write *sobj, + const char *name, unsigned int value, + size_t size, unsigned char bind, + unsigned char type, unsigned short int shndx, unsigned char st_other) { simple_object_symbol *symbol; - symbol=XNEW(simple_object_symbol); - symbol->next=NULL; - symbol->name=xstrdup(name); - symbol->align=align; - symbol->size=size; + symbol = XNEW(simple_object_symbol); + symbol->next = NULL; + symbol->name = xstrdup(name); + symbol->value = value; + symbol->size = size; + symbol->bind = bind; + symbol->type = type; + symbol->shndx = shndx; + symbol->st_other = st_other; if(sobj->last_symbol==NULL) { - sobj->symbols=symbol; - sobj->last_symbol=symbol; + sobj->symbols = symbol; + sobj->last_symbol = symbol; } else { - sobj->last_symbol->next=symbol; - sobj->last_symbol=symbol; + sobj->last_symbol->next = symbol; + sobj->last_symbol = symbol; } } @@ -576,6 +638,7 @@ simple_object_release_write (simple_object_write *sobj) while (section != NULL) { struct simple_object_write_section_buffer *buffer; + struct simple_object_write_section_relocation *relocation; simple_object_write_section *next_section; buffer = section->buffers; @@ -589,6 +652,14 @@ simple_object_release_write (simple_object_write *sobj) XDELETE (buffer); buffer = next_buffer; } + while (relocation != NULL) + { + struct simple_object_write_section_relocation *next_relocation; + + next_relocation = relocation->next; + XDELETE (relocation); + relocation = next_relocation; + } next_section = section->next; free (section->name); -- 2.42.0