Closed jeffpanici75 closed 3 years ago
That would be very helpful. At the moment the project has two assemblers: bbasmb_arm_32.c which is a naive ARM32 assembler (with currently no support for floating-point or SIMD instructions) and bbasmb_x86_64.c (a table-based x86-64 assembler with fairly good coverage of unprivileged instructions). They should tell you all you need to know about the interface to the rest of BBC BASIC. I'm guessing that an aarch64 assembler would be somewhere in between in terms of complexity.
Sounds good. I'll follow the style present in the existing modules and rename the bbasmb_arm_64.TODO.c and put the new implementation there. Are there are guidelines you'd like me to follow for the pull request?
Are there are guidelines you'd like me to follow for the pull request?
Nothing that I'm aware of, but at the age of 68 I struggle to keep up with these new-fangled ways of working!
Hi, Jeff, just to let you know that I've been working on this for the last few days. I'm probably duplicating your work, but it's worth it to get a good understanding of the Aarch64 machine code. We've been communicating at the link below, but Richard suggested I should write something here, instead:
I've started work on an ARM64 assembler. Every now and then I stick the code at http://mdfs.net/Software/ARM/Assembler/
I've been ploughing through arithmetic and logic, and have got to loads and stores, which was the stumbling block when I started looking at this, so before going further it's probably best to compare what we've each got to.
The thing that was the steep initial step was actually getting a full, complete, list of absolutely all instructions, and their binary encoding. Ok, two things, I'll get the comfy chair. Every other CPU I've written an assembler for it's been simple to find a summary for the entire instruction set that fits on one or two pages - the ARM32 fits on half a page of A5! I ploughed through the 8000-page ARM reference Richard linked to and got it down to about four pages. OpsSorted.txt at the link.
But the next problem is that a lot of instructions don't actually map to the binary instruction in any properly meaningful manner. So I had gone down a dead end of previous assemblers where, eg, b6-b3=operation, b2-b0=address mode, and all operations can use all address modes. I was stuck trying to build a binary representation of all the different LD and ST instructions, but different LD/ST have different address modes they can use. Even worse, LDR/STR allow different registers that none of the other LD/ST instructions use.
Effectively they are all different instructions, and it's much easier to code the assembler to treat them as different instructions, so that's the stage I've got to so far, albeit the reference codes are built up from a bitmap of LD/ST, data size, signed/unsigned, pair/unpaired.
So it would be valuable to compare where we've each got to before plough further in different directions.
Work has been keeping me extra busy and I haven't had a chance to start looking into this. I don't want to hold up progress others are making on this front. I'm excited to follow progress!
I had similar problems, and just went for a brute force approach and refined the way I dealt with each instruction as I went along. Anyway, here's my approach, it's about 5000 lines of code. I think it assembles every instruction, the question is if it does it properly!
There are instructions in there that will never be used by someone writing BASIC. I'd like to work out a way to automatically compare the output listing of the assembler with the output from a full-blown assembler. I've checked a few examples, obviously, but it's hardly been rigorous.
Do you know if there's a way to configure BASIC as a command-line program, so it's possible to take a dissassembly, turn it into a BASIC program, then compare the output with the original?
Do you know if there's a way to configure BASIC as a command-line program, so it's possible to take a dissassembly, turn it into a BASIC program, then compare the output with the original?
Yes, configuring BBC BASIC as a command-line assembler is relatively straightforward. However it involves using the mode in which the 'program counter' and the 'code origin' are separated (achieved by setting bit 2 of OPT) and I don't know whether you've implemented that (yet). I'll throw together a little program based on the 64-bit x86 edition that you can try.
Yes, there's definitely a problem with opt 7 and O%, I took a disassembly of some other code and hacked it into a BASIC program, but the jump and literal LDR locations were absolute and nowhere near the location of the allocated memory, so that reported many errors. I "solved" it by adding P% to the locations, because using O% just crashed BASIC.
That mod would be great. (I'm running BASIC on a PC, so I can't actually run the generated code.)
I used BASIC to write the assembled code to a file, then:
od -t x4 -Ax aarch64code.bbc | less aarch64-none-elf-objcopy -I binary -O elf64-littleaarch64 -B aarch64 aarch64code.bbc aarch64code.o aarch64-none-elf-objdump --disassemble-all aarch64code.o | less
Spoiler alert: there are bugs!
Literally the second instruction was wrong. Affecting or using SP with an ADD (and related instructions) has to use extended register or immediate, not shifted register (which should be obvious from the use of <Wd|WSP> as opposed to simply
simply < Wd >
I'll throw together a little program based on the 64-bit x86 edition that you can try.
Sorry I haven't done this yet, hopefully I may get around to it tomorrow.
Here you go. This program assembles the source file specified on the command line. Note that it doesn't work in the Windows console-mode edition of BBC BASIC; I am investigating that. But it should be OK in the GUI versions and in the console-mode editions on other platforms.
REM Assembles the file specified on the command line
INSTALL @lib$ + "stringlib"
sp% = FNinstrq(@cmd$, " ", 0)
IF sp% srcfile$ = MID$(@cmd$, sp%+1) ELSE srcfile$ = @cmd$
p%% = 0 : REM Code origin
REM Find base filename:
dot% = FN_instrr(srcfile$, ".", 0)
dir% = FN_instrr(srcfile$, "/", 0)
IF dir% = 0 dir% = FN_instrr(srcfile$, "\", 0)
IF dot% > dir% base$ = LEFT$(srcfile$, dot%-1) ELSE base$ = srcfile$
REM Open input file:
srcfile% = OPENIN(srcfile$)
IF srcfile% = 0 ERROR 0, "Couldn't open file " + srcfile$
REM Create output files:
binfile$ = base$ + ".bin"
binfile% = OPENOUT(binfile$)
IF binfile% = 0 ERROR 0, "Couldn't create file " + binfile$
lstfile$ = base$ + ".lst"
lstfile% = OPENOUT(lstfile$)
IF lstfile% = 0 ERROR 0, "Couldn't create file " + lstfile$
CLOSE #lstfile%
tmpfile$ = @tmp$ + "assemble.tmp.bbc"
REM Allocate memory for assembled code:
DIM o%% 1000000 : l%% = o%% + 1000000
REM Two pass assembly:
FOR pass% = 12 TO 15 STEP 3
PTR#srcfile% = 0
lino% = 0
tmpfile% = OPENOUT(tmpfile$)
PROCputline(tmpfile%, 0, "[OPT " + STR$pass%)
WHILE NOT EOF#srcfile%
src$ = FNgetline(srcfile%)
lino% += 1
IF ASCsrc$ <> &25 PROCputline(tmpfile%, lino%, src$)
ENDWHILE
PROCputline(tmpfile%, lino%, "]")
BPUT #tmpfile%, 0
CLOSE #tmpfile%
]^L% = l%% : ]^O% = o%% : ]^P% = p%%
OSCLI "spool """ + lstfile$ + """"
ON ERROR LOCAL IF FALSE THEN
CALL tmpfile$
ELSE
e$ = REPORT$
I% = INSTR(e$, " in module")
IF I% e$ = LEFT$(e$, I%-1)
PRINT e$ + " at line "; ERL
ENDIF : RESTORE ERROR
IF ERR = 17 EXIT WHILE
*SPOOL
NEXT pass%
CLOSE #srcfile%
FOR C% = 0 TO ]^P% - p%% - 1
BPUT#binfile%, o%%?C%
NEXT
CLOSE #binfile%
PRINT "Assembly completed, output in " binfile$ ", listing in " lstfile$
END
DEF FNgetline(F%)
LOCAL A$
A$ = GET$#F%
IF A$ = "" IF PTR#F%>1 THEN PTR#F%=PTR#F%-2:IF BGET#F%<>BGET#F% A$=GET$#F%
= A$
DEF PROCputline(F%, L%, s$)
BPUT #F%, LEN(s$) + 4
BPUT #F%, L% MOD 256
BPUT #F%, L% DIV 256
PRINT #F%, s$
ENDPROC
DEF FNinstrq(A$, B$, S%)
LOCAL I%, Q%
REPEAT
I% = INSTR(A$, B$, S%)
Q% = INSTR(A$, """", S%)
IF Q%=0 OR I%<Q% THEN = I%
S% = INSTR(A$, """", Q%+1)+1
UNTIL S%=1
= 0
Very nice! I only just spotted the console directory...
I get an error: File or path not found at line 4 4 INSTALL @lib$ + "stringlib"
Here's a slightly more readable version of what went before, with a couple of bugs fixed for good measure... bbasmb_arm_64.c.zip
In case it's not clear, generally (once I got the hang of it, at least), the I grouped mnemonics by related syntax and/or function (which usually implies encoding), the code identifies what variation of syntax is being used, checks the parameters for size and value, initialises the bit pattern in instruction according to the subset of mnemonics being assembled, finally filling in the parameters in their appropriate places.
I should probably revisit the various LDR/STR options, which were one of the first things I worked on, there's no doubt some more commonality there than I initially noticed.
For what it's worth, the code is packed with "magic numbers", but my justification for that is that if any of them changed, it wouldn't be the same processor we're assembling for. It also makes certain mistakes easier to spot; just look for duplicate patterns!
Which I've just done, and found several more mistakes! :(
I get an error: File or path not found at line 4
That shouldn't happen if you've installed from the binary distribution, the zip file extracts all the files (including the libraries) to the correct relative places. If you're building from source you need to make sure you run the binary in the project directory (note that the last line of the makefile is cp bbcbasic ../../
).
So simple! Thanks, that's what I was missing. It works fine, now.
I was just pondering what a rigorous test would look like, and I realised: computers are fast, these days!
I just tried running seq 0 $(( 0xffffffff )), and only takes just over a minute, even on this old PC; I can probably run every possible 32-bit value into a disassembler, put that into the assembler, and compare the output to the input, and it won't take more than an hour or so!
I can probably run every possible 32-bit value into a disassembler
So long as the disassembler behaves sensibly when presented with a non-existent opcode, anyway. That's one advantage of a CPU with a fixed instruction length; try generating every possible x86-64 instruction, which can be from one byte to 16 bytes in length!
Yes! Real life isn't as accommodating as I'd hoped, I wonder if the disassembler from objdump is usable, without having to write files and execute processes for every value...
Undefined instructions are easy, it writes, e.g.: 0: 000251c1 .inst 0x000251c1 ; undefined
Oh, look. There are an awful lot of floating point and SIMD instructions...
383 variations, in fact. :(
There are an awful lot of floating point and SIMD instructions...
Indeed. All I would ask is that any assembler is architecturally capable of being extended to handle them at some future point. My current 32-bit ARM assembler doesn't support them, and they're not necessary for the profiling and debugging capabilities that are the principal application for assembly language (i.e. writing interrupt service routines, which you can't do in BASIC). Do you happen to know whether any version of Acorn's ARM BASIC V assembler supports them?
ARM BBC BASIC V has the following, I guess QADD, etc. are FP?
HELP [ Assembly language is contained in [] and assembled at P%. Labels follow '.'. Syntax: SWI|SVC|DBG|HVC|SMC|SMI[
] BFC[ ] ,# ,# BFI|SBFX|UBFX[ ] , ,# ,# USAT|SSAT[ ] ,# , USAT16|SSAT16[ ] ,# , UXTB|UXTB16|UXTH|UXTAB|UXTAB16|UXTAH|SXTB|SXTB16|SXTH[ ] , BKPT|HLT|UDF ADC|ADD|AND|BIC|EOR|ORR|RSB|RSC|SBC|SUB[ ][S] , , MOV|MVN[ ][S] , MOV[T|W][ ,# CMN|CMP|TEQ|TST[ ][S|P] , CLZ|RBIT|REV|REVSH|REV16[ ] , CRC32[C]<B|H|W> , , QADD[8|16]|QSUB[8|16]|USAD8|USADA8|QDADD|QDSUB[ ] , , UADD|UHADD|UQADD|UQSUB|USUB|SADD|SHADD|SSUB|SHSUB<8|16>[ ] , , QASX|QSAX|UQASX|UQSAX|SHASX|SHSAX|SSAX|SASX|USAX|UASX|SEL[ ] , , MUL[ ][S] , , MLA|MLS|UMULL|UMLAL|SMULL|SMLAL[ ][S] , , , UMAAL[ ] , , , SMUL<W|B|T><B|T>[ ] , , SMLA[L]<W|B|T><B|T>[ ] , , , SM<LA[L]|LS[L]|UA|US>D[X][ ] , , , SMM<LA|LS|UL>[R][ ] , , , LDR|STR[ ][B|T|BT|SB|SBT|H|HT|SH|SHT|D] , '[ [, ] '] [, ][!] LDA|STL[ ][B|H] , '[ '] LDREX|LDAEX|STREX|STLEX[B|H|D][ ] , '[ '] LDM|STM[ ]DA|DB|EA|ED|FA|FD|IA|IB [!],{ }[^] RFE<DA|DB|EA|ED|FA|FD|IA|IB> [!] SRS<DA|DB|EA|ED|FA|FD|IA|IB> SP[!],# SWP[ ][B] , , '[ '] PLD[W]|PLI '[ [, ] '] PKH<BT|TB>[ ] , , PUSH|POP[ ] B[L][ ]
I've hacked (really hacked, you don't want to know!) together a test which will take a few hours to run through every possible instruction, and came across an oddity: the disassembler from binutils' objdump ignores (probably correctly) bits that are shown as (1) in an instruction description, so I'll have to do some post-processing on the test output. As long as there's one OK result for a given assembly instruction, it's OK.
grep 'stlxrb.*w8, w19, [x0]' /media/simon/OS/Other/All.txt 08088013 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 08088413 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 08088813 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 08088C13 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 08089013 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 08089413 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 08089813 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 08089C13 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808A013 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808A413 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808A813 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808AC13 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808B013 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808B413 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808B813 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808BC13 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808C013 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808C413 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808C813 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808CC13 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808D013 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808D413 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808D813 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808DC13 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808E013 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808E413 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808E813 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808EC13 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808F013 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808F413 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808F813 stlxrb w8, w19, [x0] -> 0808FC13 FAILED 0808FC13 stlxrb w8, w19, [x0] -> 0808FC13 OK
On 04-06-2021 13:47, Simon-Willcocks wrote:
Oh, look. There are an awful lot of floating point and SIMD instructions...
383 variations, in fact. :(
Yes, that got me tearing my hair. Tootling along doing alu instructions, all common addressing modes, make a start on loads & stores, many common addressing modes.... ah! STR and LDR can change to be completely different instructions, but only after you've worked out what registers it is using. Grrrr. On any other platform they would be eg FLDR and FSTR or something.
I've made a start going through your (Simon's) code. I think most of mine can be thrown away, but I think I've got some optimisations.
I started with Richard's method of having a mnenionuc opcode lookup table for the base code for each instruction that is then modified by the specific instruction, so eg
case (various arithmetic): instruction=opcode[menemoic]<<24; ... if (immediate) instruction |= something
instead of case blah: instruction=foo case blah: instruction=foo case blah: instruction=foo case blah: instruction=foo etc.
You can get most instructions into an 8-bit byte, where you can't you add the extra bits in the instruction-specific code.
I also made the reg() routine return the register width in the top two bits, so then it can be OR'd striaght into the instruction, eg: r=reg(); instruction |= (r & BIT31) | (r & 31); // Rd comma(); r=reg(); instruction |= (r & BIT31) | ((r & 31)<<5); // Rn etc.
It has the side effect that an instruction is "promoted" to the biggest register used, eg:
add w1,w2,x3 is assembled as add x1,x2,x3
I hadn't yet got to the point of making a decision as to if this should be allowed, or be an assembly error. For the latter you'd collect the 'width' bits across the instruction and then fault if they all don't match. I think the maximum number of registers usable is four, so I think I'd set the top four bits from the reg() routine and do something like:
r=reg(); width |= (r & BIT31); instruction |= (r & BIT31) | (r & 31); // Rd comma(); r=reg(); width |= (r & BIT30); instruction |= (r & BIT31) | ((r & 31)<<5); // Rn comma(); r=reg(); width |= (r & BIT29); instruction |= (r & BIT31) | ((r & 31)<<10); // Rm ... if ((width == 0) || (width == (14<<28)) else error("Mixed register widths"); // %000xxx -> all 32-bit, %111xxx -> all 64-bit
-- J.G.Harston - @.*** - mdfs.net/jgh
I made a similar change, but I used bits 5 and 6, so you can say if (32 == reg_size( r )...
The automated test has thrown up several problems, usually having to do with me not being able to count bits. It works through every possible opcode in about 2 hours, but the disassembler apparently knows instructions I don't (saddv, anyone?), and the output files are a bit excessive.
-rwxrwxrwx 1 simon simon 79G Jun 6 16:29 /media/simon/OS/Other/All.txt -rwxrwxrwx 1 simon simon 43G Jun 6 16:29 /media/simon/OS/Other/Fail.txt -rwxrwxrwx 1 simon simon 36G Jun 6 16:29 /media/simon/OS/Other/Pass.txt
I'm having difficulty attaching the latest version, I'll try again in a minute.
Half the instructions that have a bit to say it's working on a 64-bit register have them at bit 30!
(Upload still not working, sorry!)
Not sure this will be helpful to others but thought I'd mention it. ARM releases their architecture specifications as executable code: https://developer.arm.com/-/media/developer/products/architecture/armv8-a-architecture/A64_v82A_ISA_xml_00bet3.1.tar.gz
If you unpack this tarball there's a folder with an XML file for every valid instruction encoding. The XML includes ASL for both the decoding and execution of every instruction. Note that ASL is like any other programming language: it has shared code (libraries) that are found in other directories of this archive. Every aspect of the hardware is described this way. ARM uses this for automated verification but we could use it to automate building an assembler/disassembler. ARM has an example ASL interpreter: https://github.com/ARM-software/asl-interpreter
I'm sure there are other ASL interpreters written in more popular languages but I never bothered looking because I'm OK working with OCaml.
Anyhow, I was going to machine generate most (all?) of the assembler/disassembler this way.
Wow, I never expected something so powerful to be publically available! I might have a look at starting again and auto-generating the same kind of code...
On the other hand, testing is ongoing.
I worked out how to deal with encodings that don't match my encodings for the same assembly instruction: if the instruction I generate from the disassembly of the instruction we're looking it, I disassemble my attempt and compare the two assembly instructions. If they match, I count that as a "win" (labelled duplicate).
Apparently "adr xzr, address" is valid assembler and "adr sp, address" isn't. Strange.
Hey, uploads are working again! bbasmb_arm_64.c.zip
Does anyone know what on earth the difference is between:
ldrsb wzr, [sp, xzr, sxtx #0] and ldrsb wzr, [sp, xzr, sxtx]
(Other than the S bit has to be set in the former?)
"
But what difference does it make?
I'm guessing none. Is there some reason why you think there is, or should be, a difference?
There's a bit to say if it's there or not!
There's a bit to say if it's there or not!
Yes, but isn't this a case where the S bit is common across a number of different instructions, in most of which it does have an effect but in the case of this particular instruction variant it doesn't? Normally S indicates an optional shift of the index value: a shift of 4 bits (16) with a 128-bit load, 3 bits (8) with a 64-bit load, 2 bits (4) with a 32-bit load and 1 bit (2) with a 16-bit load. But when it's an 8-bit load, as in this case, there is no option to shift the index, even though the S bit is still present in the instruction encoding. Hence whether you set it or not, the shift is zero.
In the specific case of this instruction an assembler might typically accept either no shift value, in which case it would not set the S bit, or a shift of #0 (that being the only allowed value), in which case it would set the S bit. The effect would be identical, and setting the S bit indicative only of how the programmer coded the instruction. But more generally it would accept either no shift value (setting S to zero) or the unique allowed value of #0, #1, #2, #3 or #4 as appropriate (setting S to one).
Yes, it looks like it "only" hurts my testing.
If anyone's still paying attention, the latest version, as far as I can tell, handles all the basic instructions correctly. What's left are the FP/SIMD instructions, and instructions introduced since the version of the DDI0487 (C) I was working with until recently. For some reason, I didn't expect more instructions to be added to a processor!
At least, of the 1,533,460,215 instructions objdump thinks are valid, none of them are assembled to the wrong instruction. But there are nearly 750 instruction classes that aren't assembled, yet.
It occurs to me that, perhaps, FP and SIMD instructions are important to BASIC programmers trying to extract more speed from their programs? bbasmb_arm_64.c.zip
I don't know if I can upload my test program, because it involves GNU code, and if I release it, it might infect BBCSDL. (And it's pretty ugly!) It runs through every possible instruction in about ninety minutes.
It occurs to me that, perhaps, FP and SIMD instructions are important to BASIC programmers trying to extract more speed from their programs?
It's potentially the case, certainly, but since the 32-bit ARM assembler in BBCSDL doesn't currently support FP or SIMD instructions, anybody writing cross-platform code is going to be stuck anyway.
I'll try incorporating your code in an experimental build of BBCSDL; watch this space!
Preliminary results from trying to incorporate your code in the Console Edition build for the 'Apple Silicon' Mac (compiled using clang). It is issuing four warnings, not necessarily serious but best eliminated (a couple look like they might be an unwise assumption about the signedness of 'char', which varies between platforms):
You're right, I didn't spot the first two because the tests all use lower case. Just change the declaration of code to unsigned char *code. The third is a hangover from earlier, when the value was inverted (a mistake), the line can simply by deleted. The rest are because the variable is not set in the default case of the switch, which never returns anyway, and will go away by simply initialising only_32bit to 0.
I will watch this space more carefully, and press refresh from time to time! bbasmb_arm_64.c.zip
I will watch this space more carefully, and press refresh from time to time!
Great, thanks. Sadly your latest version is not compiling in clang, there are two warnings but more seriously it is reporting an implicit function declaration:
Ooh, my mistake! I used to have a function for SIMD instructions, then I thought I might as well just put it in the massive switch statement with the others, and I forgot to get rid of the other calls. Just a minute.
How about this? bbasmb_arm_64.c.zip
How about this?
That's much better. I'm still getting the two warnings (see screen shot below) which can probably be fixed by casts, but they shouldn't be affecting operation. I've noticed a couple of anomalies related to the displayed listing (compare the output from yours with the 64-bit x86 assembler, below):
[nop
nothing is displayed but if instead I enter [nop:
(with a trailing colon) it is. It looks like the listing is somehow being 'deferred' until the following instruction rather than being output immediately.The warnings can probably be avoided by removing the "unsigned", that's just me being dumb.
I don't think my stuff has a lot to do with displaying the opcodes, and when I try it on console/linux, it shows a space, but nothing with just "[nop", strangely. I'll have a look.
It's probably because I changed:
case 0x0D:
newlin () ;
if (*esi == 0x0D)
break ;
case ':':
if (liston & BIT4)
{
to:
case 0x0D:
newlin () ;
if (esi == 0x0D || esi == '\0')
break ;
case ':':
if (liston & BIT4)
{
I can't remember why I did that.
It works better without the change.
The warnings can probably be avoided by removing the "unsigned"
Oh. Isn't the "unsigned" the one you added to eliminate the previous 'comparison always fails' warnings (caused by 'char' being equivalent to 'signed char')?
I don't think my stuff has a lot to do with displaying the opcodes
It's definitely behaving differently from the bbasmb_x86_64.c code from which you probably copied it.
and when I try it on console/linux, it shows a space
Are you sure that's not simply because the allocated memory happen to be in the bottom 4 Gbytes and therefore needs only a 32-bit address? You should be printing 16 hex digits.
"Oh. Isn't the "unsigned" the one you added to eliminate the previous 'comparison always fails' warnings (caused by 'char' being equivalent to 'signed char')?" Yes, but I'm sometimes stupid! It's got to be cast to the same type it's being compared to.
I copied from bbasmb_arm_32.c.
The sprintfs still have a space after the oldpc, I don't know what's going on there.
I copied from bbasmb_arm_32.c. The sprintfs still have a space after the oldpc, I don't know what's going on there.
Ah, if you copied the formatting of the listing from a 32-bit assembler it's bound to be wrong for a 64-bit assembler (twice as many hex digits in the address field!). bbasmb_x86_64.c has:
sprintf (t, "%016llX ", (long long) oldpc) ;
I can make the change if you would prefer me to.
I made the changes in this version. bbasmb_arm_64.c.zip
I understand you're looking for support implementing an AArch64 inline assembler, which I'd be happy to do. Let me know how you'd like to proceed.