# Tag Info

## Hot answers tagged assembly

12

I have some ideas about how you might be able to improve your program. Avoid problems Rather than trying to deal with the problem for every instruction, one approach is avoiding it entirely. One way to do that is to simply append a number of bytes to the end of the vector. If the maximum bytes for an instruction is $n$, then append $n-1$ bytes to the ...

6

In a high-level language, I would write it as: def put_nibble(buf: array[byte], n: int): buf[0] = '0' + ((n shr 3) bitand 1) buf[1] = '0' + ((n shr 2) bitand 1) buf[2] = '0' + ((n shr 1) bitand 1) buf[3] = '0' + ((n shr 0) bitand 1) def char_to_nibble(ch: byte) -> int: if '0' <= ch <= '9': return ch ch = ch bitor 0x20 # ...

6

You have all the elements. The only thing that can be eliminated is jmp .run, as follows: org 0x100 mov si, Prompt call puts ret puts: mov ah, 0xe mov bx, 7 .read: lodsb or al, al jnz .post ret .post: int 0x10 jmp .read Prompt: db 'Hello World', 0 ...

6

I'm mostly reviewing the code-gen choices, not the style / implementation of the compiler itself. The compiler itself mostly looks fine in the parts I've skimmed over (looking for how it uses the format strings). The design is pretty clear and easy to dive into, and the C is well-formatted. It could be simpler and/or more efficient in some cases. (e.g. ...

6

I think the big switch is a problem. Consider a more data-driven approach where each opcode is described by a struct: struct OpCode { unsigned char command_byte; unsigned char mask; // if only a subset of bits determine command unsigned char length; // other members as needed - e.g. a pointer to the "print" function }; Now, the code that ...

5

The code looks straight-forward and really optimized for size and simplicity. There's a small detail that I would change, though: replace cmove with cmovz, to make the code more expressive. It's not that "being equal" would be of any interest here, it's the zeroness of %ecx that is interesting. I like the omitted second jmp in memmove. It's obvious after ...

5

Style feedback on how clear my comments were and how easy the code was to follow I'm not a big fan of line comments. I think they make the code a bit harder to follow. That's why I prefer tail comments along with a nice tabular layout of the labels, instructions, operands, and tail comments. And of course don't write redundant comments like "Update the ...

5

I was thinking if I should add labels like write even if I wouldn't jmp to them, so code would be cleaner. Writing labels that aren't jumped to is fine. Provided they have meaningful names, it can help to understand the program. My comments (not in a particular order) ;esi=1 mov esi, 1 This is a redundant comment! I already can see what the instruction ...

4

Undefined Behaviour If you execute this code with n DB 0, it returns without setting ch to any value, leaving the result as undefined. Signed Length mov dl,0h mov dh,n cmp dl,dh jge end If n happens to be between 128 and 255, the jge will treat the comparison as if it was a signed comparison, and since 0 is not greater than or equal to any value between ...

4

Barring any compiler heroics, you are computing n*n a total of $n^3$ times. You might want to cache that result. const int nn = n*n; B[j + n_times_i] is a linearly increasing address location, given that j increases by 1 for each middle loop, and and i increases once for each outer loop, which is n increases of j. Taking advantage of that, you can skip ...

4

20+ percent faster using the stack for the extra buffer. Matrix Question Answer(1) Faster ------------------------------------------- 16 x 16 3.62 µsec 2.62 µsec 27.6 % 13 x 13 2.67 µsec 2.05 µsec 23.2 % 10 x 10 1.77 µsec 1.35 µsec 23.7 % 7 x 7 1.02 µsec 0.77 µsec 24.5 % 4 x 4 0.56 µsec 0.44 µsec ...

4

You're treating comparison of addresses as signed values, instead of unsigned. For example, after you execute cmp bufferOffset, bufferTail, you use the jge condition, which is jump greater or equal. This is intended for signed values. You should use jae jump above or equal instruction instead. This condition needs to be changed in several places. Rather ...

4

mov SS, AX ; mov BP, 0x7BFF mov SP, BP This is a dangerous construct! To maintain a consistent SS:SP pair of registers you should always set these back to back (No instruction(s) in between). The code uses pusha, popa, shr bx, 12, ... So your code is clearly targetting x86 (and not the infamous 8086). Then you don't need to use ...

4

Linux has the sendfile system call, which copies data between file descriptors instead of copying the data to userspace and back to kernel space. That may be more efficient. Your code looks very clean and organized. If you had used named constants instead of magic numbers, you might not even need some of the comments: mov rdx, tax mov rsi, but ...

4

mov dl, byte [ecx] cmp dl, 0; read byte and comp to 0 je _exit There are various alternatives, for example: cmp byte [ecx], 0 je _exit And: mov dl, [ecx] ; note: BYTE would be redundant, but you can put it if you like test dl, dl jz _exit For that loop overall, _label: mov dl, byte [ecx] cmp dl, 0; read byte and comp to 0 je _exit add ...

3

There's plenty to optimize here! In NASM you get the address simply by writing mov di, prompt. This has a shorter encoding than lea di, [prompt]. (In MASM this would be mov di, offset prompt giving the same benefit over the lea form). Instead of writing the pair mov ah, 0x4c mov al, 0, you could combine these in 1 instruction as mov ax, 0x4C00. This ...

3

The operation count can be reduced, by using that some bits are moved by the same distance. Bits 0, 1 and 2 can be shifted left in one go. 5 and 6 can be shifted right in one go. Some shift/bitwise-OR combinations can be written as lea, that would be bad for Pentium 4 but very good on Ryzen and Ice Lake and fine on Haswell/Skylake. Since this is 64bit code ...

3

My equivalent to your nice quine is a bit nicer, and differs in other ways. It is nicer in that the payload at the end of the source is split into several lines. It still uses over-wide lines because the indentation and the blanks before comments are repeated verbatim, and each line is prefixed with a db " directive (the prefix) that is itself indented. It ...

3

There's a bug in your code if memchr finds %sil in the last byte of %rdi; if %rcx tests to be zero and yet the byte has been found, it will incorrectly return zero. To fix that, do something like this: .globl memchr memchr: mov %rdx, %rcx movzbl %sil, %eax repne scasb sete %cl lea -1(%rdi), %rax test %cl, %cl ...

3

Here's the 16-bit 8086 source to my bit mirror function, inputs are bx:dx for the size (question wants 32 there) and dword [hhvar] for the data to be bit-mirrored, output is in bx:dx. Like vnp also suggested I use rcl. I shift right bx:dx and then rotate-with-carry-left into si:di. of_bit_mirror: mov cx, dx test bx, bx jnz .large ...

3

Optimizations Why are you so keen on zeroing the registers at the completion of the program? Drop those and you'll have made your first optimization already. Don't use mov si, 0 to zero the register. Use xor si, si. It's shorter (codesize) and faster (execution speed). Instead of using lea bx, array use mov bx, array (NASM style) or mov bx, offset array (...

3

Here are some things that may help you improve your program Use consistent formatting The code as posted has irregular indentation, making it not so easy to read. Assembly language programs are typically very linear and neat. Also, I personally don't use tab characters in my code so that it looks the same everywhere (including printing), but that's a ...

3

A code-size optimization If you move the mov edi, Metrics instruction to just below the FindMatch label and thus have it repeat with each iteration, you can remove 4 instructions from the code. I've marked these with an exclamation mark: xor edx, edx mov ecx, edx FindMatch: mov edi, Metrics ;Restore it from here ...

3

Your code's division into functions isn't very natural. The objective is to have each function performing one specific task, which should also be as orthogonal as possible to the tasks performed by the other functions. For instance, your disassemble function performs three different functions: it reads from the instruction stream, it interprets assembly code ...

3

It's fine to write this scan macro for educational purposes, but I think that considering its length a subroutine would have been more appropriate. The macro's bytes are inserted everywhere the macro is invoked. That adds up! Having that many duplicated bytes in a program is a waste of space. Some observations push bp mov ah, 0Eh ; print the ...

2

Ok, old question. But no accepted answer and I've got some thoughts, so... My first thought on reading this code was to suggest you re-arrange your compares, so that you can "drop through" rather than doing an additional jump. If you move this to the end of your compare block: cmp currentCharacter, DOUBLE_QUOTE ; compare [currentCharacter] to ...

2

General/Style Line up instructions and operands in vertical columns to improve readability (like you've done with the comments); e.g.: mov var6, WINDOWS_NULL ; put pointer to template handle into parameter slot 6 call CreateFile ; create file handle cmp rax, WINDOWS_INVALID_HANDLE ; validate file handle je ...

2

When setting up the SS:SP registers, there is a slight chance that an interrupt might happen between setting SS and SP. The interrupt handler would then write to an unintended memory address. To prevent this, enclose the code between cli and sti. I'd rather set SP to 07FEh, to align memory reads to 2-byte boundaries. Instead of jmp \$ you should not waste ...

2

a. Shortest minus 1 The Q4 program contains a 2-byte xor dx,dx that you can rapidly replace by the 1-byte cwd instruction. Just bring that mov ax,484Eh on top. The positive number in AX will make cwd clear DX. B8 4E 48 mov ax,484Eh (*) 99 cwd B2 FC mov dl,252 89 D7 mov di,dx D1 E8 shr ax,1 89 45 21 mov [di+33],ax B8 ...

2

or rcx, 0xFFFFFFFFFFFFFFFF This is an optimization for size, but it does not break the dependency on the old value of rcx (at least not yet, maybe someday, it's not an impossible feature). That's a minor point compared to overall cost of a strlen but it's something to know so you can make the choice deliberately. cld Should be redundant, typical calling ...

Only top voted, non community-wiki answers of a minimum length are eligible