[qfcc] Support alignment in qfo spaces

The alignment is specified as a power of 2 (ie, actual alignment = 1 <<
alignment) allowing old object files to be compatible (as their
alignment is 0). This is necessary for (in part for #30) as it turned
out even global vectors were not aligned correctly.

Currently, only data spaces even vaguely respect alignment. This may
need to be fixed in the future.
This commit is contained in:
Bill Currie 2022-07-30 21:21:31 +09:00
parent 732ea3a5fd
commit f4ae24e0e0
7 changed files with 68 additions and 28 deletions

View file

@ -56,6 +56,7 @@ typedef struct defspace_s {
struct def_s *defs; ///< list of defs using this space
struct def_s **def_tail; ///< for appending to \a defs
pr_type_t *data; ///< backing memory for this space
int alignment; ///< minimum alignment of the whole space
int size; ///< current high-water mark for alloced data
int max_size; ///< size of backing memory, or highwater mark
///< for ds_virtual

View file

@ -91,7 +91,8 @@ typedef struct qfo_space_s {
pr_uint_t data; ///< byte offset in qfo
pr_uint_t data_size; ///< in elements. zero for entity spaces
pr_uint_t id;
pr_int_t reserved[2];
pr_uint_t alignment; ///< min alignment for space (1<<alignment)
pr_int_t reserved[1];
} qfo_space_t;
/** Representation of a def in the object file.
@ -259,6 +260,7 @@ typedef struct qfo_mspace_s {
};
pr_uint_t data_size;
pr_uint_t id;
pr_uint_t alignment;
} qfo_mspace_t;
/** In-memory representation of a QFO object file.

View file

@ -242,6 +242,8 @@ void reloc_def_op (const struct ex_label_s *label,
void reloc_attach_relocs (reloc_t *relocs, reloc_t **location);
extern const char * const reloc_name[];
///@}
#endif//__reloc_h

View file

@ -198,6 +198,9 @@ defspace_alloc_aligned_loc (defspace_t *space, int size, int alignment)
}
ofs = space->size;
pad = alignment * ((ofs + alignment - 1) / alignment) - ofs;
if (alignment > space->alignment) {
space->alignment = alignment;
}
space->size += size + pad;
if (space->size > space->max_size) {
if (!space->grow || !space->grow (space))
@ -263,7 +266,7 @@ defspace_add_data (defspace_t *space, pr_type_t *data, int size)
{
int loc;
loc = defspace_alloc_loc (space, size);
loc = defspace_alloc_highwater (space, size);
if (data)
memcpy (space->data + loc, data, size * sizeof (pr_type_t));
return loc;
@ -285,6 +288,9 @@ defspace_alloc_aligned_highwater (defspace_t *space, int size, int alignment)
int ofs = space->size;
int pad = alignment * ((ofs + alignment - 1) / alignment) - ofs;
if (alignment > space->alignment) {
space->alignment = alignment;
}
space->size += size + pad;
if (space->size > space->max_size) {
if (!space->grow || !space->grow (space))

View file

@ -559,6 +559,17 @@ add_code (qfo_mspace_t *code)
work->spaces[qfo_code_space].data_size = work_code->size;
}
static void
align_data (int space, qfo_mspace_t *data)
{
if (space < 0 || space >= qfo_num_spaces || !work_spaces[space])
linker_internal_error ("bad space for align_data (): %d", space);
defspace_alloc_aligned_highwater (*work_spaces[space], 0,
1 << data->alignment);
work->spaces[space].data = (*work_spaces[space])->data;
work->spaces[space].data_size = (*work_spaces[space])->size;
}
/** Add the data in a data space to the working qfo.
\param space The space to which the data will be added.
@ -603,6 +614,7 @@ add_data_space (qfo_t *qfo, qfo_mspace_t *space)
}
ws->data_size = space->data_size;
ws->id = space->id;
ws->alignment = space->alignment;
}
static defref_t *
@ -765,8 +777,14 @@ process_code_space (qfo_t *qfo, qfo_mspace_t *space, int pass)
static int
process_data_space (qfo_t *qfo, qfo_mspace_t *space, int pass)
{
if (pass != 1)
return 0;
if (pass == 0) {
if (space->id == qfo_near_data_space) {
align_data (qfo_near_data_space, space);
} else if (space->id == qfo_far_data_space) {
align_data (qfo_far_data_space, space);
} else {
}
} else if (pass == 1) {
if (space->id == qfo_near_data_space) {
add_defs (qfo, space, work->spaces + qfo_near_data_space,
process_data_def);
@ -778,6 +796,7 @@ process_data_space (qfo_t *qfo, qfo_mspace_t *space, int pass)
} else {
add_data_space (qfo, space);
}
}
return 0;
}
@ -797,10 +816,12 @@ process_strings_space (qfo_t *qfo, qfo_mspace_t *space, int pass)
static int
process_entity_space (qfo_t *qfo, qfo_mspace_t *space, int pass)
{
if (pass != 1)
return 0;
if (pass == 0) {
align_data (qfo_entity_space, space);
} else if (pass == 1) {
add_defs (qfo, space, work->spaces + qfo_entity_space, process_field_def);
add_data (qfo_entity_space, space);
}
return 0;
}
@ -915,14 +936,16 @@ process_type_space (qfo_t *qfo, qfo_mspace_t *space, int pass)
static int
process_debug_space (qfo_t *qfo, qfo_mspace_t *space, int pass)
{
if (pass != 1)
return 0;
if (space->type != qfos_debug) {
linker_internal_error ("bad space type for add_data_space (): %d",
linker_internal_error ("bad space type for process_debug_space (): %d",
space->type);
}
if (pass == 0) {
align_data (qfo_debug_space, space);
} else if (pass == 1) {
add_defs (qfo, space, work->spaces + qfo_debug_space, process_data_def);
add_data (qfo_debug_space, space);
}
return 0;
}
@ -1032,9 +1055,6 @@ linker_add_qfo (qfo_t *qfo)
qfo_mspace_t *space;
qfo_type_defs = 0;
for (i = 0; i < qfo_num_spaces; i++) {
work_base[i] = work->spaces[i].data_size;
}
work_func_base = work->num_funcs;
for (pass = 0; pass < 2; pass++) {
for (i = 0, space = qfo->spaces; i < qfo->num_spaces; i++, space++) {
@ -1045,6 +1065,11 @@ linker_add_qfo (qfo_t *qfo)
if (funcs[space->type] (qfo, space, pass))
return 1;
}
for (i = 0; i < qfo_num_spaces; i++) {
if (pass == 0) {
work_base[i] = work->spaces[i].data_size;
}
}
}
process_funcs (qfo);
process_lines (qfo);

View file

@ -237,6 +237,7 @@ qfo_init_data_space (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs,
memcpy (space->data, data->data, size);
}
space->data_size = data->size;
space->alignment = qfo_log2 (data->alignment);
}
static void
@ -250,6 +251,7 @@ qfo_init_entity_space (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs,
space->data = 0;
space->data_size = data->size;
space->id = qfo_entity_space;
space->alignment = qfo_log2 (data->alignment);
}
static void
@ -501,6 +503,7 @@ qfo_write (qfo_t *qfo, const char *filename)
}
spaces[i].data_size = LittleLong (qfo->spaces[i].data_size);
spaces[i].id = LittleLong (qfo->spaces[i].id);
spaces[i].alignment = LittleLong (qfo->spaces[i].alignment);
}
for (i = 0; i < qfo->num_relocs; i++) {
relocs[i].space = LittleLong (qfo->relocs[i].space);
@ -608,6 +611,7 @@ qfo_read (QFile *file)
qfo->spaces[i].data_size, qfo->spaces[i].type);
}
qfo->spaces[i].id = LittleLong (spaces[i].id);
qfo->spaces[i].alignment = LittleLong (spaces[i].alignment);
}
for (i = 0; i < qfo->num_relocs; i++) {
qfo->relocs[i].space = LittleLong (qfo->relocs[i].space);
@ -1041,7 +1045,7 @@ qfo_to_progs (qfo_t *in_qfo, int *size)
// these are in order in which they usually appear in the file rather
// than the order they appear in the struct, though with the offsets
// it doesn't matter too much. However, as people expect a certain
// layout, ti does matter enough to preserve the traditional file order.
// layout, it does matter enough to preserve the traditional file order.
progs->strings.offset = *size;
progs->strings.count = qfo->spaces[qfo_strings_space].data_size;

View file

@ -53,7 +53,7 @@
static reloc_t *refs_freelist;
static const char *reloc_name[] = {
const char * const reloc_name[] = {
"rel_none",
"rel_op_a_def",
"rel_op_b_def",