3 ms·
But then there's that "msg.len", which I assume is some sort of assembler shortcut for getting the length of an array and not part of the x86.
by nsxwolf 8y ago
But then there's that "msg.len", which I assume is some sort of assembler shortcut for getting the length of an array and not part of the x86.
- pjc50 8y agoThat's referring to the label msg.len, which is a value computed at compile time in the 'data' section at the bottom. msg: db "Hello, world!", 10 .len: equ $ - msg 'msg' is a label, which will be assigned to an address at compile time. 'db' short for 'declare bytes' puts some bytes at that address. '.len' is then defined as the current output address ($) minus the start of the string.
- e12e 8y agoIn addition to all these excellent comments, it can also be instructive to go "backwards" from C, here on Linux: cat hello.c #include <unistd.h> char str[] = "Hello, World!\n"; int main() { write(1, str, sizeof(str)-1); return 0; } cat hello.s .file "hello.c" .intel_syntax noprefix .globl str .data .align 8 .type str, @object .size str, 15 str: .string "Hello, World!\n" .text .globl main .type main, @function main: .LFB0: .cfi_startproc push rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp .cfi_def_cfa_register 6 mov edx, 14 lea rsi, str[rip] mov edi, 1 call write@PLT mov eax, 0 pop rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0" .section .note.GNU-stack,"",@progbits Note the line: lea rsi, str[rip] which I belive is something along the lines of load effective address (lea), into rsi register, of "str" symbol offset with relative instruction pointer (rip - to allow for relative addressing). You can compile and run with: gcc -std=c11 hello.c && ./a.out Prouduce hello.s from hello.c with: gcc -std=c11 hello.c -S -masm=intel
- eterps 8y agoThis makes it even easier: https://news.ycombinator.com/edit?id=17341952 https://news.ycombinator.com/edit?id=17341952
- cesarb 8y ago"lea" is a fun instruction. Going piece by piece: on x86, each register has several sizes. For instance, rax is a 64-bit register, with its lower 32-bit half being eax, its lower 16-bit half being ax, and its lower 8-bit half being al (for historical reasons). So when a register name starts with "r", it's the 64-bit variant. Therefore, "rip" is the 64-bit address of the next instruction. The instruction "mov rsi, str[rip]" would get the 64-bit address of the next instruction, add to it a fixed offset (which the assembler and linker compute for you, as the exact offset you need to get to the data at the "str" label), load 64 bits from that address, and put the result in the "rsi" register. And that's not even the most complex addressing mode; you can get a register, add to it another register multiplied by 2, 4, or 8, add to it a constant, and use it as the memory address to load, store, or even modify in-place. The "lea" instruction (load effective address) is a way to get directly at the power of that complex address calculation logic for your own uses. Instead of using the computed memory address to get at the memory, it's the memory address that's put in the register. Therefore, where "mov rsi, str[rip]" would read from memory, "lea rsi, str[rip]" would put in rsi the memory address the "mov" would have read from. This also allows for a few tricks. For instance, you can use "lea" to multiply a number by five, without using the multiplier: just use a register and the same register scaled by 4 (and you can also add a constant to the result, still in a single complex instruction).