Re: [hatari-devel] Symbol loading for upcoming MINT+ELF program format

[ Thread Index | Date Index | More lists.tuxfamily.org/hatari-devel Archives ]


On Montag, 28. August 2023 22:41:13 CEST Eero Tamminen wrote:

> Please use the same (linux style) formatting as rest of the file.


Ok. New version attached below. I have done that manually, so i hope i didn't miss anything. If i've seen correctly, that only affects putting curly braces on the same line as if/else etc?


BTW, there are other parts in the source (from my previous patches for a.out and Pure-C) that also use a different style. Should those be fixed too?


>Elf header processing in symbols_load_binary() is large enough that�

>contents for the "/* new MiNT+ELF */" block should be in a separate�

>function.


Hm, it's about the same as the extended a.out processing. And putting that into a separate function is a bit troublesome, since it accesses lots of locals from that function. And the compiler would inline that anyway again, since it is only called once.


>and keep only�

>generic parts in symbols-common.c (which e.g. includes the others).�

>Comments?


Hm, maybe. But the file is still not too large i think, splitting it would make it more difficult to read.


>NetBSD boot fails earlier than without it


Yes, it did not look into that again. It's difficult to see whats going on without access to real hw. Unfortunately my try to use the serial port of the falcon that i once sent to mikro didn't work either (the official version only has support for the MFP serial)

diff --git a/src/debug/symbols-common.c b/src/debug/symbols-common.c
index b5b8959c..31ecc485 100644
--- a/src/debug/symbols-common.c
+++ b/src/debug/symbols-common.c
@@ -51,8 +51,9 @@ typedef struct {
 } ignore_counts_t;
 
 /* Magic used to denote different symbol table formats */
-#define SYMBOL_FORMAT_GNU  0x474E555f	/* "MiNT" */
-#define SYMBOL_FORMAT_MINT 0x4D694E54	/* "GNU_" */
+#define SYMBOL_FORMAT_GNU  0x474E555f	/* "GNU_" */
+#define SYMBOL_FORMAT_MINT 0x4D694E54	/* "MiNT" */
+#define SYMBOL_FORMAT_ELF  0x454c4600	/* "ELF" */
 #define SYMBOL_FORMAT_DRI  0x0
 
 /* Magic identifying Atari programs */
@@ -883,6 +884,281 @@ static symbol_list_t* symbols_load_gnu(FILE *fp, const prg_section_t *sections,
 	return list;
 }
 
+/**
+ * Load symbols of given type and the symbol address addresses from
+ * ELF format symbol table, and add given offsets to the addresses.
+ * Return symbols list or NULL for failure.
+ */
+
+#define SIZEOF_ELF32_SYM 16
+
+#define ELF_ST_BIND(val)		(((unsigned int)(val)) >> 4)
+#define ELF_ST_TYPE(val)		((val) & 0xF)
+#define ELF_ST_INFO(bind,type)		(((bind) << 4) + ((type) & 0xF))
+
+/* sh_type */
+#define SHT_NULL		  0 		  /* Section header table entry unused */
+#define SHT_PROGBITS	  1 		  /* Program specific (private) data */
+#define SHT_SYMTAB		  2 		  /* Link editing symbol table */
+#define SHT_STRTAB		  3 		  /* A string table */
+#define SHT_RELA		  4 		  /* Relocation entries with addends */
+#define SHT_HASH		  5 		  /* A symbol hash table */
+#define SHT_DYNAMIC 	  6 		  /* Information for dynamic linking */
+#define SHT_NOTE		  7 		  /* Information that marks file */
+#define SHT_NOBITS		  8 		  /* Section occupies no space in file */
+#define SHT_REL 		  9 		  /* Relocation entries, no addends */
+#define SHT_SHLIB		  10		  /* Reserved, unspecified semantics */
+#define SHT_DYNSYM		  11		  /* Dynamic linking symbol table */
+#define SHT_INIT_ARRAY	  14		  /* Array of constructors */
+#define SHT_FINI_ARRAY	  15		  /* Array of destructors */
+#define SHT_PREINIT_ARRAY 16		  /* Array of pre-constructors */
+#define SHT_GROUP		  17		  /* Section group */
+#define SHT_SYMTAB_SHNDX  18		  /* Extended section indices */
+
+/* ST_BIND */
+#define STB_LOCAL  0				/* Symbol not visible outside obj */
+#define STB_GLOBAL 1				/* Symbol visible outside obj */
+#define STB_WEAK   2				/* Like globals, lower precedence */
+#define STB_LOOS   10				/* Start of OS-specific */
+#define STB_GNU_UNIQUE	10			/* Symbol is unique in namespace */
+#define STB_HIOS   12				/* End of OS-specific */
+#define STB_LOPROC 13				/* Application-specific semantics */
+#define STB_HIPROC 15				/* Application-specific semantics */
+
+/* ST_TYPE */
+#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 associated with a section */
+#define STT_FILE	4				/* Symbol gives a file name */
+#define STT_COMMON	5				/* Symbol is a common data object */
+#define STT_TLS 	6				/* Symbol is thread-local data object*/
+#define STT_LOOS	10				/* Start of OS-specific */
+#define STT_GNU_IFUNC	10			/* Symbol is an indirect code object */
+#define STT_HIOS	12				/* End of OS-specific */
+#define STT_LOPROC	13				/* Application-specific semantics */
+#define STT_HIPROC	15				/* Application-specific semantics */
+
+/* special sections indexes */
+#define SHN_UNDEF 0
+#define SHN_LORESERVE    0xFF00         /* Begin range of reserved indices */
+#define SHN_LOPROC       0xFF00         /* Begin range of appl-specific */
+#define SHN_HIPROC       0xFF1F         /* End range of appl-specific */
+#define SHN_LOOS         0xFF20         /* OS specific semantics, lo */
+#define SHN_HIOS         0xFF3F         /* OS specific semantics, hi */
+#define SHN_ABS          0xfff1         /* Associated symbol is absolute */
+#define SHN_COMMON       0xfff2         /* Associated symbol is in common */
+#define SHN_XINDEX		 0xFFFF			/* Section index is held elsewhere */
+#define SHN_HIRESERVE    0xFFFF         /* End range of reserved indices */
+
+/* Values for section header, sh_flags field. */
+#define SHF_WRITE			 ((uint32_t)1 << 0)   /* Writable data during execution */
+#define SHF_ALLOC			 ((uint32_t)1 << 1)   /* Occupies memory during execution */
+#define SHF_EXECINSTR		 ((uint32_t)1 << 2)   /* Executable machine instructions */
+#define SHF_MERGE			 ((uint32_t)1 << 4)   /* Might be merged */
+#define SHF_STRINGS 		 ((uint32_t)1 << 5)   /* Contains nul-terminated strings */
+#define SHF_INFO_LINK		 ((uint32_t)1 << 6)   /* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER		 ((uint32_t)1 << 7)   /* Preserve order after combining */
+#define SHF_OS_NONCONFORMING ((uint32_t)1 << 8)   /* Non-standard OS specific handling
+										   required */
+#define SHF_GROUP			 ((uint32_t)1 << 9)   /* Section is member of a group. */
+#define SHF_TLS 			 ((uint32_t)1 << 10)  /* Section hold thread-local data. */
+#define SHF_COMPRESSED		 ((uint32_t)1 << 11)	/* Section with compressed data */
+#define SHF_MASKOS			 0x0ff00000 /* OS-specific. */
+#define SHF_MASKPROC		 0xf0000000 /* Processor-specific */
+#define SHF_ORDERED 		 ((uint32_t)1 << 30)  /* Special ordering requirement
+										   (Solaris). */
+#define SHF_EXCLUDE 		 ((uint32_t)1 << 31)  /* Section is excluded unless
+										   referenced or allocated (Solaris).*/
+
+struct elf_shdr {
+    uint32_t sh_name;           /* Section name */
+    uint32_t sh_type;           /* Type of section */
+    uint32_t sh_flags;          /* Miscellaneous section attributes */
+    uint32_t sh_addr;           /* Section virtual addr at execution */
+    uint32_t sh_offset;         /* Section file offset */
+    uint32_t sh_size;           /* Size of section in bytes */
+    uint32_t sh_link;           /* Index of another section */
+    uint32_t sh_info;           /* Additional section information */
+    uint32_t sh_addralign;      /* Section alignment */
+    uint32_t sh_entsize;        /* Entry size if section holds table */
+};
+
+static symbol_list_t* symbols_load_elf(FILE *fp, const prg_section_t *sections, uint32_t tablesize, uint32_t stroff, uint32_t strsize, const symbol_opts_t *opts, struct elf_shdr *headers, unsigned short e_shnum)
+{
+	size_t slots = tablesize / SIZEOF_ELF32_SYM;
+	size_t i;
+	size_t strx;
+	unsigned char *p;
+	char *name;
+	symbol_t *sym;
+	symtype_t symtype;
+	uint32_t address;
+	uint32_t nread;
+	symbol_list_t *list;
+	uint32_t st_size;
+	unsigned char st_info;
+	unsigned char st_other;
+	unsigned short st_shndx;
+	static char dummy[] = "<invalid>";
+	int count;
+	ignore_counts_t ignore;
+	const prg_section_t *section;
+	unsigned char *symtab;
+	struct elf_shdr *shdr;
+
+	if (!(list = symbol_list_alloc(slots))) {
+		return NULL;
+	}
+
+	list->strtab = (char *)malloc(strsize);
+	symtab = (unsigned char *)malloc(tablesize);
+
+	if (list->strtab == NULL || symtab == NULL) {
+		perror("");
+		free(symtab);
+		symbol_list_free(list);
+		return NULL;
+	}
+
+	nread = fread(symtab, tablesize, 1, fp);
+	if (nread != 1) {
+		perror("ERROR: reading symbols failed");
+		free(symtab);
+		symbol_list_free(list);
+		return NULL;
+	}
+
+	if (fseek(fp, stroff, SEEK_SET) < 0) {
+		perror("ERROR: seeking to string table failed");
+		free(symtab);
+		symbol_list_free(list);
+		return NULL;
+	}
+
+	nread = fread(list->strtab, strsize, 1, fp);
+	if (nread != 1) {
+		perror("ERROR: reading symbol names failed");
+		free(symtab);
+		symbol_list_free(list);
+		return NULL;
+	}
+
+	p = (unsigned char *)symtab;
+	sym = list->names;
+
+	memset(&ignore, 0, sizeof(ignore));
+	count = 0;
+
+	for (i = 0; i < slots; i++) {
+		strx = get_be32(p);
+		p += 4;
+		address = get_be32(p);
+		p += 4;
+		st_size = get_be32(p);
+		p += 4;
+		st_info = *p++;
+		st_other = *p++;
+		st_shndx = be_swap16(*(uint16_t*)p);
+		p += 2;
+		name = dummy;
+		if (!strx) {
+			ignore.invalid++;
+			continue;
+		}
+		if (strx >= strsize) {
+			fprintf(stderr, "symbol name index %x out of range\n", (unsigned int)strx);
+			ignore.invalid++;
+			continue;
+		}
+		name = list->strtab + strx;
+
+		section = NULL;
+		switch (st_info) {
+		case ELF_ST_INFO(STB_LOCAL, STT_OBJECT):
+		case ELF_ST_INFO(STB_GLOBAL, STT_OBJECT):
+		case ELF_ST_INFO(STB_WEAK, STT_OBJECT):
+		case ELF_ST_INFO(STB_LOCAL, STT_FUNC):
+		case ELF_ST_INFO(STB_GLOBAL, STT_FUNC):
+		case ELF_ST_INFO(STB_WEAK, STT_FUNC):
+		case ELF_ST_INFO(STB_LOCAL, STT_COMMON):
+		case ELF_ST_INFO(STB_GLOBAL, STT_COMMON):
+		case ELF_ST_INFO(STB_WEAK, STT_COMMON):
+		case ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE):
+		case ELF_ST_INFO(STB_LOCAL, STT_NOTYPE):
+		case ELF_ST_INFO(STB_WEAK, STT_NOTYPE):
+			switch (st_shndx) {
+			case SHN_ABS:
+				symtype = SYMTYPE_ABS;
+				break;
+			case SHN_UNDEF:
+				/* shouldn't happen here */
+				ignore.undefined++;
+				continue;
+			case SHN_COMMON:
+				fprintf(stderr, "WARNING: ignoring common symbol '%s' in slot %u.\n", name, (unsigned int)i);
+				ignore.debug++;
+				continue;
+			default:
+				if (st_shndx >= e_shnum) {
+					ignore.invalid++;
+					continue;
+				} else {
+					shdr = &headers[st_shndx];
+					if (shdr->sh_type == SHT_NOBITS) {
+						symtype = ELF_ST_BIND(st_info) == STB_WEAK ? SYMTYPE_WEAK : SYMTYPE_BSS;
+						section = &(sections[2]);
+					} else if (shdr->sh_flags & SHF_EXECINSTR)
+					{
+						symtype = ELF_ST_BIND(st_info) == STB_WEAK ? SYMTYPE_WEAK : SYMTYPE_TEXT;
+						section = &(sections[0]);
+					} else
+					{
+						symtype = ELF_ST_BIND(st_info) == STB_WEAK ? SYMTYPE_WEAK : SYMTYPE_DATA;
+						section = &(sections[1]);
+					}
+				}
+			}
+			break;
+
+		case ELF_ST_INFO(STB_LOCAL, STT_FILE): /* filename symbol */
+			ignore.debug++;
+			continue;
+
+		case ELF_ST_INFO(STB_LOCAL, STT_SECTION): /* section name */
+			continue;
+
+		default:
+			fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %u of unknown type 0x%x.\n", name, (unsigned int)i, st_info);
+			ignore.invalid++;
+			continue;
+		}
+
+		if (section) {
+			address += sections[0].offset;	/* all GNU symbol addresses are TEXT relative */
+			if (address > section->end) {
+				fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %u with invalid offset 0x%x (>= 0x%x).\n",
+					name, symbol_char(symtype), (unsigned int)i, address, section->end);
+				ignore.invalid++;
+				continue;
+			}
+		}
+		sym->address = address;
+		sym->type = symtype;
+		sym->name = name;
+		sym++;
+		count++;
+		(void)st_other;
+		(void)st_size;
+	}
+	list->symbols = slots;
+	list->namecount = count;
+
+	free(symtab);
+
+	show_ignored(&ignore);
+	return list;
+}
 
 /* ---------- program info + symbols loading ------------- */
 
@@ -912,6 +1188,9 @@ static bool symbols_print_prg_info(uint32_t tabletype, uint32_t prgflags, uint16
 	case SYMBOL_FORMAT_GNU:	 /* "GNU_" */
 		info = "GCC/MiNT executable, a.out symbol table";
 		break;
+	case SYMBOL_FORMAT_ELF:
+		info = "GCC/MiNT executable, elf symbol table";
+		break;
 	case SYMBOL_FORMAT_DRI:
 		info = "TOS executable, DRI / GST symbol table";
 		break;
@@ -959,6 +1238,8 @@ static symbol_list_t* symbols_load_binary(FILE *fp, const symbol_opts_t *opts,
 	uint32_t symoff = 0;
 	uint32_t stroff = 0;
 	uint32_t strsize = 0;
+	struct elf_shdr *headers = 0;
+	uint16_t e_shnum = 0;
 
 	/* get TEXT, DATA & BSS section sizes */
 	fseek(fp, 2, SEEK_SET);
@@ -1055,11 +1336,109 @@ static symbol_list_t* symbols_load_binary(FILE *fp, const symbol_opts_t *opts,
 				a_drsize;
 		}
 	}
+	else if ((tabletype & 0xffffff00) == SYMBOL_FORMAT_ELF && (tabletype & 0xff) >= 40) { /* new MiNT+ELF */
+		uint32_t magic;
+		uint8_t e_ident[12];
+		uint32_t dummy;
+		uint32_t e_phoff, e_shoff;
+		uint16_t e_type, e_machine, e_phnum, e_shentsize, e_shstrndx;
+		uint16_t i;
+		uint16_t strtabidx;
+
+		/* skip to ELF program header */
+		fseek(fp, (tabletype & 0xff) - 28, SEEK_CUR);
+		tabletype = SYMBOL_FORMAT_ELF;
+		/* symbol table size in GEMDOS header includes space of ELF headers, ignore it */
+		tablesize = 0;
+
+		reads  = fread(&magic, sizeof(magic), 1, fp);
+		magic = be_swap32(magic);
+		/* read rest of e_ident */
+		reads += fread(e_ident, sizeof(e_ident), 1, fp);
+		reads += fread(&e_type, sizeof(e_type), 1, fp);
+		e_type = be_swap16(e_type);
+		reads += fread(&e_machine, sizeof(e_machine), 1, fp);
+		e_machine = be_swap16(e_machine);
+		if (reads == 4 &&
+			magic == 0x7f454c46 && /* '\177ELF' */
+			e_ident[0] == 1 && /* ELFCLASS32 */
+			e_ident[1] == 2 && /* ELFDATA2MSB */
+			e_type == 2 && /* ET_EXEC */
+			e_machine == 4) /* EM_68K */ {
+			reads  = fread(&dummy, sizeof(dummy), 1, fp);
+			reads += fread(&dummy, sizeof(dummy), 1, fp);
+			reads += fread(&e_phoff, sizeof(e_phoff), 1, fp);
+			e_phoff = be_swap32(e_phoff);
+			reads += fread(&e_shoff, sizeof(e_shoff), 1, fp);
+			e_shoff = be_swap32(e_shoff);
+			reads += fread(&dummy, sizeof(dummy), 1, fp);
+			reads += fread(&dummy, sizeof(dummy), 1, fp);
+			reads += fread(&e_phnum, sizeof(e_phnum), 1, fp);
+			e_phnum = be_swap16(e_phnum);
+			reads += fread(&e_shentsize, sizeof(e_shentsize), 1, fp);
+			reads += fread(&e_shnum, sizeof(e_shnum), 1, fp);
+			e_shnum = be_swap16(e_shnum);
+			reads += fread(&e_shstrndx, sizeof(e_shstrndx), 1, fp);
+			e_shstrndx = be_swap16(e_shstrndx);
+			fseek(fp, e_shoff, SEEK_SET);
+			strtabidx = -1;
+			headers = (struct elf_shdr *)malloc(sizeof(*headers) * e_shnum);
+			if (headers == NULL) {
+				perror("");
+				return NULL;
+			}
+			for (i = 0; i < e_shnum; i++) {
+				struct elf_shdr *shdr = &headers[i];
+
+				reads  = fread(&shdr->sh_name, 1, sizeof(shdr->sh_name), fp);
+				shdr->sh_name = be_swap32(shdr->sh_name);
+				reads += fread(&shdr->sh_type, 1, sizeof(shdr->sh_type), fp);
+				shdr->sh_type = be_swap32(shdr->sh_type);
+				reads += fread(&shdr->sh_flags, 1, sizeof(shdr->sh_flags), fp);
+				shdr->sh_flags = be_swap32(shdr->sh_flags);
+				reads += fread(&shdr->sh_addr, 1, sizeof(shdr->sh_addr), fp);
+				shdr->sh_addr = be_swap32(shdr->sh_addr);
+				reads += fread(&shdr->sh_offset, 1, sizeof(shdr->sh_offset), fp);
+				shdr->sh_offset = be_swap32(shdr->sh_offset);
+				reads += fread(&shdr->sh_size, 1, sizeof(shdr->sh_size), fp);
+				shdr->sh_size = be_swap32(shdr->sh_size);
+				reads += fread(&shdr->sh_link, 1, sizeof(shdr->sh_link), fp);
+				shdr->sh_link = be_swap32(shdr->sh_link);
+				reads += fread(&shdr->sh_info, 1, sizeof(shdr->sh_info), fp);
+				shdr->sh_info = be_swap32(shdr->sh_info);
+				reads += fread(&shdr->sh_addralign, 1, sizeof(shdr->sh_addralign), fp);
+				shdr->sh_addralign = be_swap32(shdr->sh_addralign);
+				reads += fread(&shdr->sh_entsize, 1, sizeof(shdr->sh_entsize), fp);
+				shdr->sh_entsize = be_swap32(shdr->sh_entsize);
+				if (shdr->sh_type == SHT_SYMTAB)
+				{
+					symoff = shdr->sh_offset;
+					tablesize = shdr->sh_size;
+					strtabidx = shdr->sh_link;
+				}
+			}
+			if (strtabidx == -1 || headers[strtabidx].sh_type != SHT_STRTAB) {
+				tabletype = 0;
+			} else {
+				stroff = headers[strtabidx].sh_offset;
+				strsize = headers[strtabidx].sh_size;
+			}
+		} else {
+			tabletype = 0;
+		}
+		if (tabletype == 0) {
+			fprintf(stderr, "ERROR: reading ELF header failed!\n");
+			free(headers);
+			return NULL;
+		}
+	}
 	if (!symbols_print_prg_info(tabletype, prgflags, relocflag)) {
+		free(headers);
 		return NULL;
 	}
 	if (!tablesize) {
 		fprintf(stderr, "ERROR: symbol table missing from the program!\n");
+		free(headers);
 		return NULL;
 	}
 	fprintf(stderr, "Program section sizes:\n  text: 0x%x, data: 0x%x, bss: 0x%x, symtab: 0x%x\n",
@@ -1070,6 +1449,7 @@ static symbol_list_t* symbols_load_binary(FILE *fp, const symbol_opts_t *opts,
 	sections[2].end = bsslen;
 	/* add suitable offsets to section beginnings & ends, and validate them */
 	if (!update_sections(sections)) {
+		free(headers);
 		return NULL;
 	}
 
@@ -1082,6 +1462,17 @@ static symbol_list_t* symbols_load_binary(FILE *fp, const symbol_opts_t *opts,
 		}
 		fprintf(stderr, "Trying to load a.out symbol table at offset 0x%x...\n", offset);
 		symbols = symbols_load_gnu(fp, sections, tablesize, stroff, strsize, opts);
+	} else if (tabletype == SYMBOL_FORMAT_ELF) {
+		/* go to start of symbol table */
+		offset = symoff;
+		if (fseek(fp, offset, SEEK_SET) < 0) {
+			perror("ERROR: seeking to symbol table failed");
+			free(headers);
+			return NULL;
+		}
+		fprintf(stderr, "Trying to load ELF symbol table at offset 0x%x...\n", offset);
+		symbols = symbols_load_elf(fp, sections, tablesize, stroff, strsize, opts, headers, e_shnum);
+		free(headers);
 	} else {
 		/* go to start of symbol table */
 		offset = 0x1C + textlen + datalen;


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/