| /* SPDX-License-Identifier: BSD-2-Clause */ |
| /* Copyright 1996-2025 The NASM Authors - All Rights Reserved */ |
| |
| #ifndef NASM_OUTLIB_H |
| #define NASM_OUTLIB_H |
| |
| #include "compiler.h" |
| #include "nasm.h" |
| #include "error.h" |
| #include "hashtbl.h" |
| #include "saa.h" |
| #include "rbtree.h" |
| |
| uint64_t realsize(enum out_type type, uint64_t size); |
| |
| /* Do-nothing versions of some output routines */ |
| enum directive_result |
| null_directive(enum directive directive, char *value); |
| void null_sectalign(int32_t seg, unsigned int value); |
| void null_reset(void); |
| int32_t null_segbase(int32_t seg); |
| |
| /* Do-nothing versions of all the debug routines */ |
| void null_debug_init(void); |
| void null_debug_linenum(const char *filename, int32_t linenumber, |
| int32_t segto); |
| void null_debug_deflabel(char *name, int32_t segment, int64_t offset, |
| int is_global, char *special); |
| void null_debug_directive(const char *directive, const char *params); |
| void null_debug_typevalue(int32_t type); |
| void null_debug_output(int type, void *param); |
| void null_debug_cleanup(void); |
| extern const struct dfmt * const null_debug_arr[2]; |
| |
| /* |
| * This macro expands the legacy output information into separate |
| * variables, to make gradual porting of backends easier. |
| */ |
| #define OUT_LEGACY(_out,_segto,_data,_type,_size,_segment,_wrt) \ |
| int32_t _segto = (_out)->loc.segment; \ |
| const void *_data = (_out)->legacy.data; \ |
| enum out_type _type = (_out)->legacy.type; \ |
| uint64_t _size = (_out)->legacy.size; \ |
| int32_t _segment = (_out)->legacy.tsegment; \ |
| int32_t _wrt = (_out)->legacy.twrt |
| |
| /* |
| * Common routines for tasks that really should migrate into the core. |
| * This provides a common interface for maintaining sections and symbols, |
| * and provide quick lookups as well as declared-order sequential walks. |
| * |
| * These structures are intended to be embedded at the *top* of a |
| * backend-specific structure containing additional information. |
| * |
| * The tokens O_Section, O_Symbol and O_Reloc are intended to be |
| * defined as macros by the backend before including this file! |
| */ |
| |
| struct ol_sect; |
| struct ol_sym; |
| |
| #ifndef O_Section |
| typedef struct ol_sect O_Section; |
| #endif |
| #ifndef O_Symbol |
| typedef struct ol_sym O_Symbol; |
| #endif |
| #ifndef O_Reloc |
| typedef void * O_Reloc; |
| #endif |
| |
| /* Common section structure */ |
| |
| /* |
| * Common flags for sections and symbols; low values reserved for |
| * backend. Note that both ol_sect and ol_sym begin with a flags |
| * field, so if a section pointer points to an external symbol instead |
| * they can be trivially resolved. |
| */ |
| #define OF_SYMBOL 0x80000000 |
| #define OF_GLOBAL 0x40000000 |
| #define OF_IMPSEC 0x20000000 |
| #define OF_COMMON 0x10000000 |
| |
| struct ol_sym; |
| |
| struct ol_symlist { |
| struct ol_symlist *next; |
| struct rbtree tree; |
| }; |
| struct ol_symhead { |
| struct ol_symlist *head, **tail; |
| struct rbtree *tree; |
| uint64_t n; |
| }; |
| |
| struct ol_sect { |
| uint32_t flags; /* Section/symbol flags */ |
| struct ol_sect *next; /* Next section in declared order */ |
| const char *name; /* Name of section */ |
| struct ol_symhead syml; /* All symbols in this section */ |
| struct ol_symhead symg; /* Global symbols in this section */ |
| struct SAA *data; /* Contents of section */ |
| struct SAA *reloc; /* Section relocations */ |
| uint32_t index; /* Primary section index */ |
| uint32_t subindex; /* Current subsection index */ |
| }; |
| |
| /* Segment reference */ |
| enum ol_seg_type { |
| OS_NOSEG = 0, /* Plain number (no segment) */ |
| OS_SEGREF = 1, /* It is a segment reference */ |
| OS_ABS = 1, /* Absolute segment reference */ |
| OS_SECT = 2, /* It is a real section */ |
| OS_OFFS = OS_SECT, /* Offset reference in section */ |
| OS_SEG = OS_SECT|OS_SEGREF /* Section reference */ |
| }; |
| |
| union ol_segval { |
| struct ol_sect *sect; /* Section structure */ |
| struct ol_sym *sym; /* External symbol structure */ |
| }; |
| |
| struct ol_seg { |
| union ol_segval s; |
| enum ol_seg_type t; |
| |
| /* |
| * For a section: subsection index |
| * For a metasymbol: virtual segment index |
| * For an absolute symbol: absolute value |
| */ |
| uint32_t index; |
| }; |
| |
| /* seg:offs representing the full location value and type */ |
| struct ol_loc { |
| int64_t offs; |
| struct ol_seg seg; |
| }; |
| |
| /* Common symbol structure */ |
| struct ol_sym { |
| uint32_t flags; /* Section/symbol flags */ |
| uint32_t size; /* Size value (for backend) */ |
| struct ol_sym *next; /* Next symbol in declared order */ |
| const char *name; /* Symbol name */ |
| struct ol_symlist syml; /* Section-local symbol list */ |
| struct ol_symlist symg; /* Section-local global symbol list */ |
| struct ol_loc p; /* Symbol position ("where") */ |
| struct ol_loc v; /* Symbol value ("what") */ |
| }; |
| |
| /* |
| * Operations |
| */ |
| void ol_init(void); |
| void ol_cleanup(void); |
| |
| /* Convert offs:seg to a location structure */ |
| extern void |
| ol_mkloc(struct ol_loc *loc, int64_t offs, int32_t seg); |
| |
| /* Get the section or external symbol from a struct ol_seg */ |
| static inline O_Section *seg_sect(struct ol_seg *seg) |
| { |
| return (O_Section *)seg->s.sect; |
| } |
| static inline O_Symbol *seg_xsym(struct ol_seg *seg) |
| { |
| return (O_Symbol *)seg->s.sym; |
| } |
| |
| /* |
| * Return a pointer to the symbol structure if and only if a section is |
| * really a symbol of some kind (extern, common...) |
| */ |
| static inline struct ol_sym *_seg_extsym(struct ol_sect *sect) |
| { |
| return (sect->flags & OF_SYMBOL) ? (struct ol_sym *)sect : NULL; |
| } |
| static inline O_Symbol *seg_extsym(O_Section *sect) |
| { |
| return (O_Symbol *)_seg_extsym((struct ol_sect *)sect); |
| } |
| |
| /* |
| * Find a section or create a new section structure if it does not exist |
| * and allocate it an index value via seg_alloc(). |
| */ |
| extern struct ol_sect * |
| _ol_get_sect(const char *name, size_t ssize, size_t rsize); |
| static inline O_Section *ol_get_sect(const char *name) |
| { |
| return (O_Section *)_ol_get_sect(name, sizeof(O_Section), sizeof(O_Reloc)); |
| } |
| |
| /* Find a section by name without creating one */ |
| extern struct ol_sect *_ol_sect_by_name(const char *); |
| static inline O_Section *ol_sect_by_name(const char *name) |
| { |
| return (O_Section *)_ol_sect_by_name(name); |
| } |
| |
| /* Find a section or external symbol by index; NULL if not valid */ |
| extern struct ol_sect *_ol_sect_by_index(int32_t index); |
| static inline O_Section *ol_sect_by_index(int32_t index) |
| { |
| return (O_Section *)_ol_sect_by_index(index); |
| } |
| |
| /* Global list of sections (not including external symbols) */ |
| extern struct ol_sect *_ol_sect_list; |
| static inline O_Section *ol_sect_list(void) |
| { |
| return (O_Section *)_ol_sect_list; |
| } |
| |
| /* Count of sections (not including external symbols) */ |
| extern uint64_t _ol_nsects; |
| static inline uint64_t ol_nsects(void) |
| { |
| return _ol_nsects; |
| } |
| |
| /* |
| * Start a new subsection for the given section. At the moment, once a |
| * subsection has been created, it is not possible to revert to an |
| * earlier subsection. ol_sect_by_index() will return the main section |
| * structure. Returns the new section index. This is used to prevent |
| * the front end from optimizing across subsection boundaries. |
| */ |
| extern int32_t _ol_new_subsection(struct ol_sect *sect); |
| static inline int32_t ol_new_subsection(O_Section *sect) |
| { |
| return _ol_new_subsection((struct ol_sect *)sect); |
| } |
| |
| /* |
| * Create a new symbol. If this symbol is OS_OFFS, add it to the relevant |
| * section, too. If the symbol already exists, return NULL; this is |
| * different from ol_get_section() as a single section may be invoked |
| * many times. On the contrary, the front end will prevent a single symbol |
| * from being defined more than once. |
| * |
| * If flags has OF_GLOBAL set, add it to the global symbol hash for the |
| * containing section. If flags has OF_IMPSEC set, allocate a segment |
| * index for it via seg_alloc() and add it to the section by index list. |
| */ |
| extern struct ol_sym *_ol_new_sym(const char *name, const struct ol_loc *v, |
| uint32_t flags, size_t size); |
| static inline O_Symbol *ol_new_sym(const char *name, const struct ol_loc *v, |
| uint32_t flags) |
| { |
| return (O_Symbol *)_ol_new_sym(name, v, flags, sizeof(O_Symbol)); |
| } |
| |
| /* Find a symbol by name in the global namespace */ |
| extern struct ol_sym *_ol_sym_by_name(const char *name); |
| static inline O_Symbol *ol_sym_by_name(const char *name) |
| { |
| return (O_Symbol *)_ol_sym_by_name(name); |
| } |
| |
| /* |
| * Find a symbol by address in a specific section. If no symbol is defined |
| * at that exact address, return the immediately previously defined one. |
| * If global is set, then only return global symbols. |
| */ |
| extern struct ol_sym *_ol_sym_by_address(struct ol_sect *sect, int64_t addr, |
| bool global); |
| static inline O_Symbol *ol_sym_by_address(O_Section *sect, int64_t addr, |
| bool global) |
| { |
| return (O_Symbol *)_ol_sym_by_address((struct ol_sect *)sect, addr, global); |
| } |
| |
| /* Global list of symbols */ |
| extern struct ol_sym *_ol_sym_list; |
| static inline O_Symbol *ol_sym_list(void) |
| { |
| return (O_Symbol *)_ol_sym_list; |
| } |
| |
| /* Global count of symbols */ |
| extern uint64_t _ol_nsyms; |
| static inline uint64_t ol_nsyms(void) |
| { |
| return _ol_nsyms; |
| } |
| |
| #endif /* NASM_OUTLIB_H */ |