Do not generally think about registers containing addresses, think of registers containing values. Those values might be treated as addresses if they are used in certain contexts.
%eax just is an expression that refers to the register called eax. Even if I started to write this paragraph in a different way, %eax is not the same as 0x100, even if the register %eax contains the value 0x100. It depends on the context in which you name a register whether the value of that register is relevant at all.
Now, you are putting parenthesis around an expression, you are indicating that you are talking about a memory location, whose address is the value of the expression. In a context where just the value of an expression is used, an expression naming a register may be replaced by a constant expression having the same value as the register. In this case (%eax) is equivalent to ($0x100) (if you may write it that way), that is, the memory location at the address 0x100. The AT&T syntax used by the GNU assembler by default lets you write just 0x100 instead of ($0x100) to refer to the memory location at address 0x100. If an instruction is going to access memory, you need to tell that instruction, what location it should access. Note that I did not talk about the way that memory is accessed, as this depends on the specific instruction.
Now, you were talking about movl $0x4050, (%eax). So the memory location is mentioned in the second operand of the move instruction. In AT&T syntax, this is the target operand of the move instruction. The target of the move instruction is in this case: "The memory location at the address indicated by the value stored in %eax", so if %eax is 0x100, the target of the move is "The memory location at the address 0x100". Note that up to now we did not talk about the contents of that memory location, just about the location itself. The mov instruction (you have to learn these specifics for any instruction) does not care about the value stored in the location indicated by the target operand, but it will store a copy of the value of the source operand at the location indicated by the second operand, overwriting the previous value. So the 0x3999 stored at address 0x100 does not matter at all, but after execution, it has been replaced by 0x4050.
movl $0x4050, %eaxputs the value0x4050into the registereax. It does not in any way use the value that was already ineax.movl $0x4050, (%eax)stores the value0x4050to memory at address0x100. It does not in any way use the value that was previously at that address. X86 assembly is difficult becausemovis overloaded to mean load from memory, store to memory, and move to register. Other assembly languages might have different opcodes for each type of move. - JS1