6 ms·
How to Read ARM64 Assembly Language
- ngcc_hk 6y agoIt would be better to have the Env setup e.g. Docker, VM etc. as it is an beginner code learning and it compares with intel code. In fact the author does include even compiler switch. But this is too partial to be useful for experimentation and visual learning
- swolchok 6y agoI haven't tried this, don't work for Amazon, and only just found out, but https://aws.amazon.com/ec2/graviton/ https://aws.amazon.com/ec2/graviton/ says that "Until June 30th 2021, all new and existing AWS customers can try the t4g.micro instances free for up to 750 hours per month". t4g.micro instances are Graviton, which is ARM64. Note that 31 days is only 744 hours. Buyer beware, though: https://aws.amazon.com/ec2/instance-types/ https://aws.amazon.com/ec2/instance-types/ only says the free trial is until March 31, 2021.
- ngcc_hk 6y agohttps://azeria-labs.com/arm-on-x86-qemu-user/ https://azeria-labs.com/arm-on-x86-qemu-user/ is one example. You can run some of it (asm64 work but not the objdump or gdb, only 32 bit?) by using the docker under macOS ``` docker run -it --entrypoint "/bin/bash" ubuntu:latest ```
- ngcc_hk 6y agoFurther if you follow the linked example I still cannot do the objdump or gdb (and hence still not reaching the goal of getting the asm reading). Back to the vector.pcc program, I can compile the vector.pcc program (after adding int main() and some cout etc.) You do need a few more apt install commands (especially the last one to add c++): ``` apt install qemu-user qemu-user-static gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu binutils-aarch64-linux-gnu-dbg build-essential apt install vim apt install arm-linux-gnueabihf apt install gdb-multiarch apt install arm-linux-gnueabihf-gcc apt install g++-aarch64-linux-gnu ``` For the vector source, I wonder why use c++ for testing instead of just c. After adding cout and int main(), the program can run. However, as the linked one seems not work for arm64 so far, I am still somewhere in between and not able to move to the reading assembly part, as the target of all test. Cannot get the ld to work but use a simpler c source can generate something like this: ``` cat vector2c.S .arch armv8-a .file "vector2.c" .text .align 2 .global normSquared .type normSquared, %function normSquared: .LFB0: .cfi_startproc sub sp, sp, #16 .cfi_def_cfa_offset 16 stp x0, x1, [sp] ldr x1, [sp] ldr x0, [sp] mul x1, x1, x0 ldr x2, [sp, 8] ldr x0, [sp, 8] mul x0, x2, x0 add x0, x1, x0 add sp, sp, 16 .cfi_def_cfa_offset 0 ret .cfi_endproc .LFE0: .size normSquared, .-normSquared .align 2 .global main .type main, %function main: .LFB1: .cfi_startproc stp x29, x30, [sp, -32]! .cfi_def_cfa_offset 32 .cfi_offset 29, -32 .cfi_offset 30, -24 mov x29, sp mov x0, 42 str x0, [sp, 16] mov x0, 12 str x0, [sp, 24] ldp x0, x1, [sp, 16] bl normSquared mov w0, 0 ldp x29, x30, [sp], 32 .cfi_restore 30 .cfi_restore 29 .cfi_def_cfa_offset 0 ret .cfi_endproc .LFE1: .size main, .-main .ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0" .section .note.GNU-stack,"",@progbits ``` from vector2.c ``` #include <stdint.h> struct Vec2 { int64_t x; int64_t y; }; int64_t normSquared(struct Vec2 v) { return v.x * v.x + v.y * v.y; } int main() { struct Vec2 v; v.x = 42; v.y = 12; normSquared(v); return 0; } ```
- tom_mellior 6y agoHacker News uses four space indentation for code blocks, not ``` markers.
- ngcc_hk 6y agoTrying VmWare, VirtualBoxVM, none work. Finally pay and run UTM. Most not working but at least the minimum Debian work. All the commands under https://azeria-labs.com/arm-on-x86-qemu-user/ https://azeria-labs.com/arm-on-x86-qemu-user/ and also this works. You need some basic gcc commands and gdb commands, plus modification of the source so to have a driving main: ``` #include <cstdint> struct Vec2 { int64_t x; int64_t y; }; int64_t normSquared(Vec2 v) { return v.x * v.x + v.y * v.y; } int main() { Vec2 v; v.x = 42; v.y = 10; int64_t x=0; x = normSquared(v); return 0; } // gcc vector.cpp -o vector -Wa,-adhln=vectorO0.s -g -march=native //gcc -ggdb3 -o vectorgdb vector.cpp //gdb vectorgdb ``` Getting the interaction working and now can be back to reading his post!
- banachtarski 6y agoHow does docker even help in this regard. If you run x86, you’d need qemu or some other emulation stack. If you run arm you just test natively
- banachtarski 6y agoAlso I thought the article is really useful given that it’s geared towards people already fluent in x86 assembly
- swolchok 6y agoI had hoped that this article wouldn’t require x86 assembly fluency to read; it really is a “port” of my prior article on x86-64 assembly. I wrote it because mobile developers, at least, probably care more about ARM64 than x86-64. Is there anything I can do to make this article similarly approachable to the x86-64 one?
- banachtarski 6y agoIt's approachable either way. The main reason I mentioned x86 familiarity is because you make references to your previous post as well. I'm already reasonably fluent in both x86 and arm assembly, so I may not be the best judge though
- JdeBP 6y agoExplaining things in terms of how they are unlike x86 is what makes people think that they need x86 knowledge as a pre-requisite. The mechanics of branch-with-link can be explained without using x86 as a base. It's a call where the return address is saved in a register and code controls where and when that address is spilled to the stack, rather than it always being on the stack. This is common to several ISAs. The explanation that sp is a "stack pointer" is like pretty much every stack-based ISA, and does not need special reference to the x86. The idea that all instructions are the same width, similarly, is common to several ISAs, and does not need special reference to only one of the architectures where it is not the case. And operand order is not unlike x86, but rather unlike a specific assembly language for x86, for which there are alternatives.
- dastx 6y ago> Next, we have madd x0, x0, x0, x8. madd stands for “multiply-add”: it squares x0, adds x8, and stores the result in x0. I'm curious (I know very little about assembly or what's on the CPU so pardon me if what I'm asking makes no sense), what's the benefit of having a whole instruction that both multiplies and adds? Is there a logical gate on the processor that does this? Or is this just going through a binary multiplier before going through an adder? Does what I'm asking even make any sense?
- JdeBP 6y agoIn terms of actual hardware, a general-purpose multiply+adder is actually just a multiplier with one extra row for the addend. NxN multipliers are implemented as an N-row addition (of one multiplicand shifted and masked by the bits of the other). One more row is very cheap compared to running two operations through an ALU that only has separate multiply and add hardware. In general, outwith ALUs as well as in, it is very cheap to fold any (reasonable) number of additions and subtractions, even ones with constant left/right shifts/rotates to the addends and subtrahends, into multipliers.
- Y_Y 6y agoAre you using the word "outwith" to be funny, or is this really idiomatic in some dialect? I've seen people using "within and without" to mean "inside of and outside of" but not in anything written in the last hundred years.
- bloak 6y agoThe word "outwith" is used in Scotland. I'm not Scottish, but I've heard Scots use the word, and Oxford English Dictionary has recent quotations for it from Scottish newspapers.
- JdeBP 6y agoAnd Hacker News within just the past 5 days. (-: * https://news.ycombinator.com/item?id=26438656 https://news.ycombinator.com/item?id=26438656 * https://news.ycombinator.com/item?id=26399177 https://news.ycombinator.com/item?id=26399177
- JdeBP 6y agoThis article makes the same mistake as the last one. The inner save and restore of SP for the variable-length array is logically disconnected from the function epilogue, and not part of it. In a more complex function the disconnect would be more clear. * https://news.ycombinator.com/item?id=26317860 https://news.ycombinator.com/item?id=26317860
- swolchok 6y agoIs there a reason that the inner save and restore must be separate? Why couldn’t peephole optimization remove them?
- JdeBP 6y agoI suspect that it's because perilogue code, of functions or of inner block scopes, simply isn't subjected to optimization, other than the settings that control the existence of framepointers, smart callbacks, and whatnot, which are fairly fixed alterations to the boilerplate. People also probably don't want to risk peephole optimizing code that has been carefully arranged to exactly match calling conventions, possibly including expectations of specific instructions in specific places. Ironically, the best optimization that isn't done to perilogues in the x86 architecture is to take out the PUSH/POP instructions and replace them with MOVs and LEAs, ironically making them more like perilogues on other ISAs. * http://jdebp.uk./FGA/function-perilogues.html#Standardx86 http://jdebp.uk./FGA/function-perilogues.html#Standardx86
- SavantIdiot 6y ago> "Unlike the x86-64 assembly syntax we used previously, the destination operand is on the left. " What? In x86 asm notation, destination is always on the left. EDIT: I've only ever used the notation defined by the Intel Programmer's Guide official documentation. My bad.
- bla3 6y agoDepends on if you're using intel asm syntax or at&t asm syntax. On Windows, intel syntax is the default, but on non-windows you get at&t unless you explicitly ask for intel. at&t asm puts destination on the right.
- SavantIdiot 6y agoOh, I was going by the Intel Programmer's Guide, not AT&T syntax.
- iFreilicht 6y agoWait, is the operand really always on the left? stp and ldp seem to be exceptions, where the two values are the left operands, and the memory location is the right. Or am I missing something here?